/******************************************************************************
 * * contact_main.c - implementation of contact main functions
 *
 * *(C) Copyright 2019 Asr International Ltd.
 * * All Rights Reserved
 * ******************************************************************************/
#include "contact_global.h"

LV_IMG_DECLARE(contact);

/**
 * Get memory selected
 * param (in) MemoryAndIndex: UINT16
 * return  UINT8
 */
UINT8 Contacts_Get_Memory_Select(CONTACTS_MEMORY Memory)
{
    if (CONTACTS_MEMORY_MAX_NUM <= Memory)
    {
        printf("%s: memory %d error\n", __FUNCTION__, Memory);
    }
    return(0x01 << Memory);
}

/**
 * Set contact memory
 * param (in) Memory: CONTACTS_MEMORY
 * return  UINT16
 */
UINT16 Contacts_Set_Contact_Memory(CONTACTS_MEMORY Memory)
{
    if (CONTACTS_MEMORY_MAX_NUM <= Memory)
    {
        printf("%s: memory %d error\n", __FUNCTION__, Memory);
    }
    return(Memory << 14); /*bit 15 and 16*/
}

/**
 * Get contact memory
 * param (in) MemoryAndIndex: UINT16
 * return  CONTACTS_MEMORY
 */
CONTACTS_MEMORY Contacts_Get_Contact_Memory(UINT16 MemoryAndIndex)
{
    return(MemoryAndIndex >> 14); /*bit 15 and 16*/
}

/**
 * Get contact index in phone/sim1/sim2
 * param (in) MemoryAndIndex: UINT16
 * return  UINT16
 */
UINT16 Contacts_Get_Contact_Index(UINT16 MemoryAndIndex)
{
    return(MemoryAndIndex & 0x3FFF); /*bit 0~14*/
}

/**
 * Get contact index in phone/sim1/sim2
 * param (in) MemoryAndIndex: UINT16
 * param (in) MemSel: UINT8
 * return  BOOL
 */
BOOL Contacts_Is_In_MemSel(UINT16 MemoryAndIndex, UINT8 MemSel)
{
    CONTACTS_MEMORY Memory = Contacts_Get_Contact_Memory(MemoryAndIndex);
    UINT8 TmpMemSel = Contacts_Get_Memory_Select(Memory);
    if (0 != (MemSel & TmpMemSel))
    {
        return(TRUE);
    }
    else
    {
        return(FALSE);
    }
}

/**
 * Read contact completely
 * param (in) VOID
 * return  VOID
 */
VOID Contacts_Read_Contact_Complete(VOID)
{
    UINT8           i;
    Contacts_List_t *Contact;
    UINT32          Len;
    UINT32          Offset;

    /* update speed dial list */
    for (i = 0; i < CONTACTS_MAX_SPEED_DIAL_KEY_NUMBER; i++)
    {
        if ('\0' != g_ContactsMng.SpeedDialList[i].Name[0])
        {
            Contact = _lv_ll_get_head(&g_ContactsMng.ContactsList);
            while (NULL != Contact)
            {
                if (  (0 == strcmp(g_ContactsMng.SpeedDialList[i].Name, Contact->ContactInfo->Name))
                   && (0 ==
                       strcmp(g_ContactsMng.SpeedDialList[i].Number, Contact->ContactInfo->Number)))
                {
                    break;
                }
                Contact = _lv_ll_get_next(&g_ContactsMng.ContactsList, Contact);
            }
            if (NULL == Contact) // the contact for speed dial absent in contacts list
            {
                Len = sizeof(Contacts_Speed_Dial_Info_t);
                Hal_Mem_Set(&g_ContactsMng.SpeedDialList[i], 0, Len);
                Offset = i * Len;
                if (Len !=
                    UI_NV_Write_Req(NV_SECTION_UI_SPEED_DIAL_LIST, Offset, Len, (UINT8 *)(&g_ContactsMng.SpeedDialList[i])))
                {
                    /* error */
                }
            }
        }
    }
}

/**
 * Add new contact to NVM
 * param (in) ContactInfo: Contacts_Info_t *
 * return  VOID
 */
VOID Contacts_Add_Contact_To_Nvm(Contacts_Info_t *ContactInfo)
{
    UINT16                        Index;
    UINT8                         Len;
#if 0
    UINT8                         Bit;
#endif
    NV_UI_Contacts_Bitmap_t       NvBitmap;
    UINT32                        Offset;
    NV_UI_Contacts_Contact_Info_t NvContact;
    UINT16                        i;
    UINT16                        ContactIndex;

    Len = sizeof(NV_UI_Contacts_Bitmap_t);
    if (Len != UI_NV_Read_Req(NV_SECTION_UI_CONTACTS_BITMAP, 0, Len, (UINT8 *)(&NvBitmap)))
    {
        UI_Log_Out(UI_SUB_MODULE_FRAMEWORK, UI_LOG_LEVEL_TRACE_3, "Contacts_Add_Contact_To_Nvm, read error\n");
        return;
    }
#if 0
    for (i = 0; i < NV_CONTACTS_MAX_CONTACT_NUM; i++)
    {
        Index = i / 8;
        Bit   = i % 8;
        if (0 == (NvBitmap.ContactBitmap[Index] & (0x01 << Bit)))
        {   /* the contact invalid at the position */
            NvBitmap.ContactBitmap[Index] |= 0x01 << Bit;
            break;
        }
    }
#else
    for (i = 0;i < NV_CONTACTS_MAX_BITMAP_LEN;i++)
    {
        if (0xFF != NvBitmap.ContactBitmap[i])
        {
            break;
        }
    }
    if (NV_CONTACTS_MAX_BITMAP_LEN == i)
    {
        printf("%s: error, contacts full in nvm\n", __FUNCTION__);
        return;
    }
    Index = i;
    for (i = 0;i < 8;i++)
    {
        if (0 == (NvBitmap.ContactBitmap[Index] & (0x01 << i)))
        {
            break;
        }
    }
    ContactIndex = 8 * Index + i;
    if (NV_CONTACTS_MAX_CONTACT_NUM < (ContactIndex + 1))
    {
        printf("%s: error 2, contacts full in nvm\n", __FUNCTION__);
        return;
    }
    NvBitmap.ContactBitmap[Index] |= 0x01 << i;
#endif
    if (1 !=
        UI_NV_Write_Req(NV_SECTION_UI_CONTACTS_BITMAP, Index, 1, &NvBitmap.ContactBitmap[Index]))
    {
        UI_Log_Out(UI_SUB_MODULE_FRAMEWORK, UI_LOG_LEVEL_TRACE_3, "Contacts_Add_Contact_To_Nvm, write error\n");
        return;
    }

    Len = sizeof(NV_UI_Contacts_Contact_Info_t);
    Hal_Mem_Set(&NvContact, 0, Len);
    Hal_Mem_Copy(NvContact.Name, ContactInfo->Name, CONTACTS_MAX_NAME_LENGTH);
    Hal_Mem_Copy(NvContact.Number, ContactInfo->Number, CONTACTS_MAX_NUMBER_LENGTH);
    NvContact.ToneIndex = IF_CONTACTS_DEFAULT_TONE;
    Offset              = Len * i;
    if (Len != UI_NV_Write_Req(NV_SECTION_UI_CONTACTS_LIST, Offset, Len, (UINT8 *)(&NvContact)))
    {
        /* error */
        return;
    }
#if 0
    ContactInfo->MemoryAndIndex += i;
#else
    ContactInfo->MemoryAndIndex += ContactIndex;
#endif
} /* Contacts_Add_Contact_To_Nvm */

/**
 * Add contact, automatically modify name if name repetition
 * param (in) ContactInfo: Contacts_Info_t *
 * param (in) Focus: Contacts_List_t **
 * return  VOID
 */
VOID Contacts_Add_Contact_With_Name_Modified(Contacts_Info_t *ContactInfo,
                                             Contacts_List_t **FocusForContacts)
{
    UINT8           Len1;
    UINT8           Len2;
    UINT8           Memory;
    UINT16          ModifyNum   = 0;
    Contacts_List_t *Focus      = NULL;
    Contacts_List_t *StartFocus = NULL;
    INT8            *Name;
    UINT8           MaxLen = CONTACTS_MAX_NAME_LENGTH - 1;

    Len1 = strlen(ContactInfo->Name);
    Name = (INT8 *)Hal_Mem_Alloc(Len1 + 1);
    Hal_Mem_Copy(Name, ContactInfo->Name, Len1 + 1);

    while (0 == Contacts_Add_Contact(ContactInfo, &Focus, FocusForContacts))
    {   /* contact name repetition in the same memory */
        /* modify contact name to new one */
        if (NULL == StartFocus)
        {
            StartFocus = Focus;
        }
        else
        {
            Focus = StartFocus;
        }

        ModifyNum++;

        if (999 < ModifyNum)
        {
            Len2 = 4;
        }
        else if (99 < ModifyNum)
        {
            Len2 = 3;
        }
        else if (9 < ModifyNum)
        {
            Len2 = 2;
        }
        else
        {
            Len2 = 1;
        }

        if (MaxLen > (Len1 + Len2))
        {
            sprintf(ContactInfo->Name, "%s%d", Name, ModifyNum);
        }
        else
        {
            /* modify the last characters to modification number */
            ContactInfo->Name[MaxLen - Len2] = '\0';
            sprintf(ContactInfo->Name, "%s%d", Name, ModifyNum);
        }
    }

    if (0 != ModifyNum)
    {
        g_ContactsMng.ContactOper.NameModifedFlg = TRUE;
    }

    Hal_Mem_Free(Name);

    Memory = Contacts_Get_Contact_Memory(ContactInfo->MemoryAndIndex);
    g_ContactsMng.PhkStatus[Memory].Used++;
} /* Contacts_Add_Contact_With_Name_Modified */

/**
 * Timer stop
 * param (in) VOID
 * return  VOID
 */
VOID Contacts_Timer_Stop(VOID)
{
    if (TRUE == g_ContactsMng.TimerRunFlg)
    {
        Hal_Timer_Stop(g_ContactsMng.TimerId);
        g_ContactsMng.TimerRunFlg = FALSE;
    }
}

/**
 * Get contacts operation list for contacts copy/move/delete/select
 * param (in) VOID
 * return  VOID
 */
lv_ll_t *Contacts_Get_Contacts_Operation_List(UINT16 *Count)
{
    lv_ll_t *ContactsList;

    if ((CONTACTS_ACTION_COPY == g_ContactsMng.ContactOper.Action)
        || (CONTACTS_ACTION_COPYING == g_ContactsMng.ContactOper.Action)
        || (CONTACTS_ACTION_MOVE == g_ContactsMng.ContactOper.Action)
        || (CONTACTS_ACTION_MOVING == g_ContactsMng.ContactOper.Action))
    {
        ContactsList = &g_ContactsMng.ContactOper.SrcMemList;
        if (NULL != Count)
        {
            *Count = g_ContactsMng.PhkStatus[g_ContactsMng.ContactOper.SrcMemory].Used;
        }
    }
    else
    {
        if (CONTACTS_MEMSEL_ALL != g_ContactsMng.ContactsMemSel.MemSel)
        {
            ContactsList = &g_ContactsMng.ContactsMemSel.ListForSpecMem;
            if (NULL != Count)
            {
                *Count = g_ContactsMng.ContactsMemSel.ContactsCount;
            }
        }
        else
        {
            ContactsList = &g_ContactsMng.ContactsList;
            if (NULL != Count)
            {
                *Count = g_ContactsMng.ContactsCount;
            }
        }
    }

    return(ContactsList);
}

/**
 * Handle direction key pressed on List control
 * param (in) Key_Val: UI_KEY_VALUE
 * return  VOID
 */
VOID Contacts_Press_Direction_Key_On_List(UI_KEY_VALUE Key_Val)
{
    UI_List_Desc_t *List;

    if (ACT_ID_CONTACTS_NOSCREEN == g_ContactsMng.InterfaceCtrl.InterfaceId)
    {
        List = &(((UI_Normal_List_Only_Desc_t *)g_ContactsMng.InterfaceCtrl.PrevCtrl)->List);
    }
    else
    {
        List = &(((UI_Normal_List_Only_Desc_t *)g_ContactsMng.InterfaceCtrl.Ctrl)->List);
    }

    switch (Key_Val)
    {
    case KEY_UP:
    case KEY_LEFT:
        if (0 != List->Index)
        {
            List->Index--;
        }
        else
        {
            List->Index = List->ListButtonCnt - 1;
        }
        break;

    case KEY_DOWN:
    case KEY_RIGHT:
        if ((List->ListButtonCnt - 1) != List->Index)
        {
            List->Index++;
        }
        else
        {
            List->Index = 0;
        }
        break;

    default:
        break;
    }
} /* Contacts_Press_Direction_Key_On_List */

/**
 * Public callback function for handling key pressed on normal list interface
 * param (in) Obj: lv_obj_t *
 * param (in) Key_Sta: UI_KEY_STATUS
 * param (in) Key_Val: UI_KEY_VALUE
 * return  UINT8
 */
UINT8 Contacts_Normal_List_Interface_Key_Cb(lv_obj_t *Obj, UI_KEY_STATUS Key_Sta,
                                            UI_KEY_VALUE Key_Val)
{
    UINT8 Ret = 1; // not call default key function for List

    if (KEY_RELEASED == Key_Sta)
    {
        switch (Key_Val)
        {
        case KEY_SOFTRIGHT:
            Nav_Back(ACT_ID_ANY);
            break;

        case KEY_END:
            Nav_Home(ACT_ID_ANY);
            break;

        case KEY_OK:
        case KEY_UP:
        case KEY_DOWN:
        case KEY_LEFT:
        case KEY_RIGHT:
            Contacts_Press_Direction_Key_On_List(Key_Val);
            Ret = 0; // call default key function for List
            break;

        default:
            break;
        } /* switch */
    }

    return(Ret);
}

/**
 * Public callback function for destroying the interface with List control which will be popped from stack
 * param (in) Ctrl: VOID *
 * return  VOID
 */
VOID Contacts_Normal_List_Interface_OnDestroy(VOID *Ctrl)
{
    UI_List_Desc_t *ListDesc = &(((UI_Normal_List_Only_Desc_t *)Ctrl)->List);
    UINT8          i;

    for (i = 0; i < ListDesc->ListButtonCnt; i++)
    {
        if (NULL != ListDesc->ButtonList[i].BtnTxt)
        {
            Hal_Mem_Free(ListDesc->ButtonList[i].BtnTxt);
        }
    }
    Hal_Mem_Free(ListDesc->ButtonList);
    Hal_Mem_Free(Ctrl);
}

/**
 * Start timer for status interface migration
 * param (in) Cb: ContactCallback
 * return  VOID
 */
VOID Contacts_Status_Interface_Timer_Start(ContactCallback Cb)
{
    UI_Log_Out(UI_SUB_MODULE_FRAMEWORK, UI_LOG_LEVEL_TRACE_2, "Contacts_Status_Interface_Timer_Start, InterfaceId %d\n", g_ContactsMng.InterfaceCtrl.InterfaceId);
    g_ContactsMng.TimerId = Hal_Timer_Start(CONTACTS_TIMER_STATUS_INTERFACE_LENGTH, Cb, (VOID *)&g_ContactsMng.InterfaceCtrl.InterfaceId, FALSE);
    g_ContactsMng.TimerRunFlg = TRUE;
}

/**
 * Go back to previous interface if timer expired
 * param (in) TimerId: UINT32
 * return  VOID
 */
VOID Contacts_Timeout_Back_To_Prev_Interface(VOID* Para)
{
    g_ContactsMng.TimerRunFlg = FALSE;
    UINT32* InterfaceId = (UINT32*)Para;
    Nav_Back(*InterfaceId);
}

/**
 * Public callback function for additional actions after Creating status interface
 * param (in) Ctrl: VOID *
 * return  VOID
 */
VOID Contacts_Status_Interface_OnCreate(VOID *Ctrl)
{
    Contacts_Status_Interface_Timer_Start(Contacts_Timeout_Back_To_Prev_Interface);
}

/**
 * Public callback function for saving state before forward to another activity
 * param (in) Ctrl: VOID *
 * return  VOID
 */
VOID Contacts_Interface_OnSaveState(VOID *Ctrl)
{
    Contacts_Timer_Stop();
}

/**
 * Public callback function for destroying interface which will be popped from stack
 * param (in) Ctrl: VOID *
 * return  VOID
 */
VOID Contacts_Interface_OnDestroy(VOID *Ctrl)
{
    Contacts_Timer_Stop();
    Hal_Mem_Free(Ctrl);
}

/**
 * Public callback function for handling key pressed on status interface
 * param (in) Obj: lv_obj_t *
 * param (in) Key_Sta: UI_KEY_STATUS
 * param (in) Key_Val: UI_KEY_VALUE
 * return  UINT8
 */
UINT8 Contacts_Status_Interface_Key_Cb(lv_obj_t *Obj, UI_KEY_STATUS Key_Sta, UI_KEY_VALUE Key_Val)
{
    if (KEY_RELEASED == Key_Sta)
    {
        switch (Key_Val)
        {
        case KEY_END:
            Nav_Home(ACT_ID_ANY);
            break;

        default:
            break;
        } /* switch */
    }

    return(1);
}

/**
 * Get memory symbol of contacts
 * param (in) MemoryAndIndex: UINT16
 * return  INT8 *
 */
INT8 *Contacts_Get_Contact_Memory_Symbol(UINT16 MemoryAndIndex)
{
    CONTACTS_MEMORY Memory = Contacts_Get_Contact_Memory(MemoryAndIndex);

    if (CONTACTS_MEMORY_PHONE == Memory)
    {
        return(SYMBOL_PHONE);
    }
    else if (CONTACTS_MEMORY_SIM1 == Memory)
    {
        return(SYMBOL_SIM1);
    }
    else
    {
        return(SYMBOL_SIM2);
    }
}

/**
 * Action if pressing add contact button on Contacts_Option interface
 * param (in) lv_obj_t *Btn,lv_event_t event
 * return  void
 */
void Contacts_Option_Btn_Add_Contact_Cb(lv_obj_t *Btn,lv_event_t event)
{
    if(LV_EVENT_CLICKED != event)
    {
        return;
    }

    g_ContactsMng.InterfaceCtrl.SrcActId = ACT_ID_CONTACTS;
    g_ContactsMng.ContactOper.Action     = CONTACTS_ACTION_ADD;
    Contacts_Create_Contacts_Add_Sel_Mem();
}

/**
 * Action if pressing search button on Contacts_Option interface
 * param (in) lv_obj_t *Btn,lv_event_t event
 * return  void
 */
void Contacts_Option_Btn_Search_Cb(lv_obj_t *Btn,lv_event_t event)
{
    if(LV_EVENT_CLICKED != event)
    {
        return;
    }

    Contacts_Create_Contacts_Search();
}

/**
 * Action if pressing copy button on Contacts_Option interface
 * param (in) lv_obj_t *Btn,lv_event_t event
 * return  void
 */
void Contacts_Option_Btn_Copy_Cb(lv_obj_t *Btn,lv_event_t event)
{
    if(LV_EVENT_CLICKED != event)
    {
        return;
    }

    Contacts_Create_Contacts_Copy_Select();
}

/**
 * Action if pressing move button on Contacts_Option interface
 * param (in) lv_obj_t *Btn,lv_event_t event
 * return  void
 */
void Contacts_Option_Btn_Move_Cb(lv_obj_t *Btn,lv_event_t event)
{
    if(LV_EVENT_CLICKED != event)
    {
        return;
    }

    Contacts_Create_Contacts_Move_Select();
}

/**
 * Action if pressing Delete button on Contacts_Option interface
 * param (in) lv_obj_t *Btn,lv_event_t event
 * return  void
 */
void Contacts_Option_Btn_Delete_Cb(lv_obj_t *Btn,lv_event_t event)
{
    if(LV_EVENT_CLICKED != event)
    {
        return;
    }

    Contacts_Create_Contacts_Delete();
}

/**
 * Action if pressing settings button on Contacts_Option interface
 * param (in) lv_obj_t *Btn,lv_event_t event
 * return  void
 */
void Contacts_Option_Btn_Settings_Cb(lv_obj_t *Btn,lv_event_t event)
{
    if(LV_EVENT_CLICKED != event)
    {
        return;
    }

    Contacts_Create_Contacts_Settings();
}

/**
 * Action if pressing speed dials button on Contacts_Option interface
 * param (in) lv_obj_t *Btn,lv_event_t event
 * return  void
 */
void Contacts_Option_Btn_Speed_Dials_Cb(lv_obj_t *Btn,lv_event_t event)
{
    if(LV_EVENT_CLICKED != event)
    {
        return;
    }

    Contacts_Create_Contacts_Speed_Dials();
}

/**
 * Action if pressing num screening button on Contacts_Option interface
 * param (in) lv_obj_t *Btn,lv_event_t event
 * return  void
 */
void Contacts_Option_Btn_Num_Scrn_Cb(lv_obj_t *Btn,lv_event_t event)
{
    if(LV_EVENT_CLICKED != event)
    {
        return;
    }

    Contacts_Create_Contacts_Noscreen();
}

/**
 * Callback function for restoring state on Contacts_Option interface after backward from another activity
 * param (in) Ctrl: VOID *
 * return  VOID
 */
VOID Contacts_Option_OnRestoreState(VOID *Ctrl)
{
    g_ContactsMng.InterfaceCtrl.Ctrl        = Ctrl;
    g_ContactsMng.InterfaceCtrl.InterfaceId = ACT_ID_CONTACTS_OPTION;
}

/**
 * Create Contacts_Option interface
 * param (in) VOID
 * return  VOID
 */
VOID Contacts_Create_Contacts_Option(VOID)
{
    UI_Normal_List_Only_Desc_t *NormalLstOnlyDesc;
    Nav_Func_List_t            FuncList;
    UINT16                     ContactTotal;
    UINT8                      i = 0;
    UINT32                     Len;

    NormalLstOnlyDesc =
        (UI_Normal_List_Only_Desc_t *)Hal_Mem_Alloc(sizeof(UI_Normal_List_Only_Desc_t));
    Hal_Mem_Set(NormalLstOnlyDesc, 0, sizeof(UI_Normal_List_Only_Desc_t));

    g_ContactsMng.InterfaceCtrl.InterfaceId = ACT_ID_CONTACTS_OPTION;
    g_ContactsMng.InterfaceCtrl.Ctrl        = (VOID *)NormalLstOnlyDesc;

    NormalLstOnlyDesc->TitleBar.TxtId      = PHONE_TEXT_ID_CONTACT;
    NormalLstOnlyDesc->TitleBar.TxtAlign   = LV_LABEL_ALIGN_CENTER;
    NormalLstOnlyDesc->TitleBar.LabelAlign = LV_ALIGN_IN_TOP_LEFT;

    if (CONTACTS_MEMSEL_ALL != g_ContactsMng.ContactsMemSel.MemSel)
    {
        ContactTotal = g_ContactsMng.ContactsMemSel.ContactsCount;
    }
    else
    {
        ContactTotal = g_ContactsMng.ContactsCount;
    }

    if (0 == ContactTotal)
    {
        NormalLstOnlyDesc->List.ListButtonCnt = 3;
    }
    else
    {
        NormalLstOnlyDesc->List.ListButtonCnt = 6;

        if (  (CONTACTS_PHONEBOOK_STATUS_READ_DONE == g_ContactsMng.PhonebookStatus[0])
           || (CONTACTS_PHONEBOOK_STATUS_READ_DONE == g_ContactsMng.PhonebookStatus[1]))
        {
            NormalLstOnlyDesc->List.ListButtonCnt += 2;
        }
    }
    Len = sizeof(UI_Button_Desc_t) *
          NormalLstOnlyDesc->List.ListButtonCnt;
    NormalLstOnlyDesc->List.ButtonList = (UI_Button_Desc_t *)Hal_Mem_Alloc(Len);
    Hal_Mem_Set(NormalLstOnlyDesc->List.ButtonList, 0, Len);

    NormalLstOnlyDesc->List.ButtonList[i].Valid        = TRUE;
    NormalLstOnlyDesc->List.ButtonList[i].SymbolId1    = SYMBOL_ADD_NAME;
    NormalLstOnlyDesc->List.ButtonList[i].ButtonIndex  = i;
    NormalLstOnlyDesc->List.ButtonList[i].TxtId        = PHONE_TEXT_ID_ADD_CONTACT;
    NormalLstOnlyDesc->List.ButtonList[i++].ReleaseFun = Contacts_Option_Btn_Add_Contact_Cb;

    if (0 != ContactTotal)
    {
        NormalLstOnlyDesc->List.ButtonList[i].Valid        = TRUE;
        NormalLstOnlyDesc->List.ButtonList[i].SymbolId1    = SYMBOL_SEARCH;
        NormalLstOnlyDesc->List.ButtonList[i].ButtonIndex  = i;
        NormalLstOnlyDesc->List.ButtonList[i].TxtId        = PHONE_TEXT_ID_SEARCH;
        NormalLstOnlyDesc->List.ButtonList[i++].ReleaseFun = Contacts_Option_Btn_Search_Cb;

        if (  (CONTACTS_PHONEBOOK_STATUS_READ_DONE == g_ContactsMng.PhonebookStatus[0])
           || (CONTACTS_PHONEBOOK_STATUS_READ_DONE == g_ContactsMng.PhonebookStatus[1]))
        {   /* SIM1 or SIM2 present */
            NormalLstOnlyDesc->List.ButtonList[i].Valid        = TRUE;
            NormalLstOnlyDesc->List.ButtonList[i].SymbolId1    = SYMBOL_CONTCOPY;
            NormalLstOnlyDesc->List.ButtonList[i].ButtonIndex  = i;
            NormalLstOnlyDesc->List.ButtonList[i].TxtId        = PHONE_TEXT_ID_COPY;
            NormalLstOnlyDesc->List.ButtonList[i++].ReleaseFun = Contacts_Option_Btn_Copy_Cb;

            NormalLstOnlyDesc->List.ButtonList[i].Valid        = TRUE;
            NormalLstOnlyDesc->List.ButtonList[i].SymbolId1    = SYMBOL_TRANSFER;
            NormalLstOnlyDesc->List.ButtonList[i].ButtonIndex  = i;
            NormalLstOnlyDesc->List.ButtonList[i].TxtId        = PHONE_TEXT_ID_MOVE;
            NormalLstOnlyDesc->List.ButtonList[i++].ReleaseFun = Contacts_Option_Btn_Move_Cb;
        }

        NormalLstOnlyDesc->List.ButtonList[i].Valid        = TRUE;
        NormalLstOnlyDesc->List.ButtonList[i].SymbolId1    = SYMBOL_TRASH;
        NormalLstOnlyDesc->List.ButtonList[i].ButtonIndex  = i;
        NormalLstOnlyDesc->List.ButtonList[i].TxtId        = PHONE_TEXT_ID_DELETE;
        NormalLstOnlyDesc->List.ButtonList[i++].ReleaseFun = Contacts_Option_Btn_Delete_Cb;
    }

    NormalLstOnlyDesc->List.ButtonList[i].Valid        = TRUE;
    NormalLstOnlyDesc->List.ButtonList[i].SymbolId1    = LV_SYMBOL_SETTINGS;
    NormalLstOnlyDesc->List.ButtonList[i].ButtonIndex  = i;
    NormalLstOnlyDesc->List.ButtonList[i].TxtId        = PHONE_TEXT_ID_SETTINGS;
    NormalLstOnlyDesc->List.ButtonList[i++].ReleaseFun = Contacts_Option_Btn_Settings_Cb;

    if (0 != ContactTotal)
    {
        NormalLstOnlyDesc->List.ButtonList[i].Valid        = TRUE;
        NormalLstOnlyDesc->List.ButtonList[i].SymbolId1    = SYMBOL_SPEED_DIAL;
        NormalLstOnlyDesc->List.ButtonList[i].ButtonIndex  = i;
        NormalLstOnlyDesc->List.ButtonList[i].TxtId        = PHONE_TEXT_ID_SPEED_DIALS;
        NormalLstOnlyDesc->List.ButtonList[i++].ReleaseFun = Contacts_Option_Btn_Speed_Dials_Cb;
    }

    NormalLstOnlyDesc->List.ButtonList[i].Valid        = TRUE;
    NormalLstOnlyDesc->List.ButtonList[i].SymbolId1    = SYMBOL_SCREENED;
    NormalLstOnlyDesc->List.ButtonList[i].ButtonIndex  = i;
    NormalLstOnlyDesc->List.ButtonList[i].TxtId        = PHONE_TEXT_ID_NSCREENING;
    NormalLstOnlyDesc->List.ButtonList[i++].ReleaseFun = Contacts_Option_Btn_Num_Scrn_Cb;

    NormalLstOnlyDesc->BtnBar.ButtonL.Valid = FALSE;
    NormalLstOnlyDesc->BtnBar.ButtonM.Valid = TRUE;
    NormalLstOnlyDesc->BtnBar.ButtonM.TxtId = PHONE_TEXT_ID_SELECT;
    NormalLstOnlyDesc->BtnBar.ButtonR.Valid = TRUE;
    NormalLstOnlyDesc->BtnBar.ButtonR.TxtId = PHONE_TEXT_ID_BACK;

    NormalLstOnlyDesc->KeyFunc = Contacts_Normal_List_Interface_Key_Cb;

    Hal_Mem_Set(&FuncList, 0, sizeof(Nav_Func_List_t));
    FuncList.OnShow         = UI_Normal_List_Only_Create;
    FuncList.OnRestoreState = Contacts_Option_OnRestoreState;
    FuncList.OnDestroy      = Contacts_Normal_List_Interface_OnDestroy;

    Nav_Forward(ACT_ID_ANY, ACT_ID_CONTACTS_OPTION, &FuncList, g_ContactsMng.InterfaceCtrl.Ctrl);
} /* Contacts_Create_Contacts_Option */

/**
 * Action if pressing contact button on Contacts interface
 * param (in) lv_obj_t *Btn,lv_event_t event
 * return  void
 */
void Contacts_Btn_Contact_Cb(lv_obj_t *Btn,lv_event_t event)
{
    if(LV_EVENT_CLICKED != event)
    {
        return;
    }

    UI_Log_Out(UI_SUB_MODULE_FRAMEWORK, UI_LOG_LEVEL_TRACE_1, "Contacts_Btn_Contact_Cb, Name %s\n", g_ContactsMng.InterfaceCtrl.FocusContact->ContactInfo->Name);
    Contacts_Create_Contacts_Details(g_ContactsMng.InterfaceCtrl.FocusContact->ContactInfo, FALSE);
}

/**
 * Update the description of buttons in UI_Button_Container_Desc_t
 * param (in) Contact: Contacts_Info_t *
 * param (in) ContBtn: UI_Button_Desc_t *
 * return  VOID
 */
VOID Contacts_Update_ContBtn_Des(Contacts_Info_t *Contact, UI_Button_Desc_t *ContBtn)
{
    lv_obj_t *Label;
    lv_obj_t *Image;
    UINT8    Len = CONTACTS_MAX_NAME_LENGTH + CONTACTS_MAX_NUMBER_LENGTH + 1;

    if (ContBtn->BtnTxt && ((Len - 1) != strlen(ContBtn->BtnTxt)))
    {
        Hal_Mem_Free(ContBtn->BtnTxt);
        ContBtn->BtnTxt = NULL;
    }
    if (NULL == ContBtn->BtnTxt)
    {
        ContBtn->BtnTxt = (INT8 *)Hal_Mem_Alloc(Len);
    }
    ContBtn->TxtId = LV_LANG_TXT_ID_NONE;
    snprintf(ContBtn->BtnTxt, Len, "%s\n%s", Contact->Name, Contact->Number);

    Image = lv_obj_get_child(ContBtn->Button, NULL);
    Label = lv_obj_get_child(ContBtn->Button, Image);
    lv_label_set_text(Label, ContBtn->BtnTxt);
    if (true == lv_obj_get_hidden(Image))
    {
        lv_obj_set_hidden(Image, false);
    }
    ContBtn->SymbolId2 = Contacts_Get_Contact_Memory_Symbol(Contact->MemoryAndIndex);
    lv_img_set_src(Image, ContBtn->SymbolId2);
}

/**
 * Press direction key on contact list interface
 * param (in) Key_Val: UI_KEY_VALUE
 * param (in) Interface: UI_Button_Container_Desc_t *
 * param (in) Focus:
 * return  UINT8: Contacts_List_t **
 */
UINT8 Contacts_Press_Direction_Key(UI_KEY_VALUE Key_Val, UI_Button_Container_Desc_t *Interface,
                                   Contacts_List_t **Focus)
{
    UINT8            Ret = 1;
    Contacts_List_t  *Contact = *Focus;
    Contacts_List_t  *ContactPrev;
    Contacts_List_t  *ContactNext;
    UINT16           ContactTotal;
    UI_Button_Desc_t *ContBtn[UI_MAX_CONT_BTN_NUM];
    lv_obj_t         *Cont;
    lv_ll_t          *ContactsList;
    INT16            i;

    for (i = 0;i < UI_MAX_CONT_BTN_NUM;i++)
    {
        ContBtn[i] = &Interface->ContButton[i];
    }
    Cont = Interface->ContScrl.Container;

    ContactsList = Contacts_Get_Contacts_Operation_List(&ContactTotal);

    if (2 > ContactTotal)
    {   /* Contact empty or only one contact, not move focus */
        return(Ret);
    }

    switch (Key_Val)
    {
    case KEY_UP:
    case KEY_LEFT:
        if (0 == Interface->Index) // focus on the first button
        {
            if (UI_MAX_CONT_BTN_NUM >= ContactTotal)
            {
                /* jump to the tail of button */
                *Focus           = _lv_ll_get_tail(ContactsList);
                Interface->Index = ContactTotal - 1;
                Ret              = 0;                         // call the default key funtion to move focus
            }
            else
            {
                ContactPrev = _lv_ll_get_prev(ContactsList, Contact);
                if (NULL != ContactPrev)
                {
                    /* only change button text to the previous contact, not move focus */
                    *Focus = ContactPrev;
                    Contacts_Update_ContBtn_Des(ContactPrev->ContactInfo, ContBtn[0]);
                    Contacts_Update_ContBtn_Des(Contact->ContactInfo, ContBtn[1]);
                    for (i = 2;i < UI_MAX_CONT_BTN_NUM;i++)
                    {
                        Contact = _lv_ll_get_next(ContactsList, Contact);
                        Contacts_Update_ContBtn_Des(Contact->ContactInfo, ContBtn[i]);
                    }

                    Interface->PosY -= Interface->Height;
                }
                else // focus at the head of contact list
                {
                    /* jump to the tail */
                    Contact = _lv_ll_get_tail(ContactsList);
                    *Focus = Contact;
                    for (i = UI_MAX_CONT_BTN_NUM - 1;i >= 0;i--)
                    {
                        Contacts_Update_ContBtn_Des(Contact->ContactInfo, ContBtn[i]);
                        Contact = _lv_ll_get_prev(ContactsList, Contact);
                    }

                    Interface->Index = UI_MAX_CONT_BTN_NUM - 1;
                    Interface->PosY  = Interface->Height * (ContactTotal - UI_MAX_CONT_BTN_NUM);

                    Ret = 0;
                }
            }
        }
        else
        {
            *Focus = _lv_ll_get_prev(ContactsList, Contact);
            Interface->Index--;

            Ret = 0; // call the default key function
        }

        Contacts_Set_ScrlBar_Pos_For_BtnCont(Cont,
                                             Interface->List,
                                             ContactTotal * Interface->Height,
                                             - Interface->PosY);
        break;

    case KEY_DOWN:
    case KEY_RIGHT:
        if (UI_MAX_CONT_BTN_NUM >= ContactTotal)
        {
            if ((ContactTotal - 1) == Interface->Index)
            {
                *Focus           = _lv_ll_get_head(ContactsList);
                Interface->Index = 0;
            }
            else
            {
                *Focus = _lv_ll_get_next(ContactsList, Contact);;
                Interface->Index++;
            }

            Ret = 0; // call the default key function
        }
        else
        {
            if ((UI_MAX_CONT_BTN_NUM - 1) == Interface->Index)   // focus on the last button
            {
                ContactNext = _lv_ll_get_next(ContactsList, Contact);
                if (NULL == ContactNext) // at the tail of contact list
                {
                    /* jump to the head of contact list */
                    Contact = _lv_ll_get_head(ContactsList);
                    Contacts_Update_ContBtn_Des(Contact->ContactInfo, ContBtn[0]);
                    *Focus = Contact;

                    for (i = 1;i < UI_MAX_CONT_BTN_NUM;i++)
                    {
                        Contact = _lv_ll_get_next(ContactsList, Contact);
                        Contacts_Update_ContBtn_Des(Contact->ContactInfo, ContBtn[i]);
                    }

                    Interface->Index = 0;
                    Interface->PosY  = 0;

                    Ret = 0;
                }
                else
                {
                    /* only change button text to the next contact, not move focus */
                    *Focus = ContactNext;
                    Contacts_Update_ContBtn_Des(ContactNext->ContactInfo, ContBtn[UI_MAX_CONT_BTN_NUM - 1]);
                    Contacts_Update_ContBtn_Des(Contact->ContactInfo, ContBtn[UI_MAX_CONT_BTN_NUM - 2]);
                    for (i = UI_MAX_CONT_BTN_NUM - 3;i >= 0;i--)
                    {
                        Contact = _lv_ll_get_prev(ContactsList, Contact);
                        Contacts_Update_ContBtn_Des(Contact->ContactInfo, ContBtn[i]);
                    }

                    Interface->PosY += Interface->Height;
                }
            }
            else
            {
                Interface->Index++;
                *Focus = _lv_ll_get_next(ContactsList, Contact);

                Ret = 0; // call the default key function
            }
        }

        Contacts_Set_ScrlBar_Pos_For_BtnCont(Cont,
                                             Interface->List,
                                             ContactTotal * Interface->Height,
                                             - Interface->PosY);
        break;

    default:
        break;
    } /* switch */

    return(Ret);
} /* Contacts_Press_Direction_Key */

/**
 * Create Contacts_No_Phone_Number interface
 * param (in) VOID
 * return  VOID
 */
VOID Contacts_Create_No_Phone_Number(VOID)
{
    UI_Status_Desc_t *StatusDesc;
    Nav_Func_List_t  FuncList;

    StatusDesc = (UI_Status_Desc_t *)Hal_Mem_Alloc(sizeof(UI_Status_Desc_t));
    Hal_Mem_Set(StatusDesc, 0, sizeof(UI_Status_Desc_t));

    g_ContactsMng.InterfaceCtrl.InterfaceId = ACT_ID_CONTACTS_NO_PHONE_NUMBER;
    g_ContactsMng.InterfaceCtrl.Ctrl        = (VOID *)StatusDesc;

    StatusDesc->ContLabel.TxtId      = PHONE_TEXT_ID_NO_NUMBERS;
    StatusDesc->ContLabel.TxtAlign   = LV_LABEL_ALIGN_LEFT;
    StatusDesc->ContLabel.LabelAlign = LV_ALIGN_IN_TOP_LEFT;
    StatusDesc->ContLabelAlign       = LV_ALIGN_IN_TOP_LEFT;

    StatusDesc->ContImg.Img  = LV_SYMBOL_WARNING;
    StatusDesc->ContImgAlign = LV_ALIGN_IN_TOP_RIGHT;

    StatusDesc->KeyFunc = Contacts_Status_Interface_Key_Cb;

    Hal_Mem_Set(&FuncList, 0, sizeof(Nav_Func_List_t));
    FuncList.OnShow    = UI_Status_Create;
    FuncList.OnCreate  = Contacts_Status_Interface_OnCreate;
    FuncList.OnDestroy = Contacts_Interface_OnDestroy;

    Nav_Forward(ACT_ID_ANY, ACT_ID_CONTACTS_NO_PHONE_NUMBER, &FuncList, g_ContactsMng.InterfaceCtrl.Ctrl);
}

/**
 * Callback function for handling key pressed on Contacts interface
 * param (in) Obj: lv_obj_t *
 * param (in) Key_Sta: UI_KEY_STATUS
 * param (in) Key_Val: UI_KEY_VALUE
 * return  UINT8
 */
UINT8 Contacts_Key_Cb(lv_obj_t *Obj, UI_KEY_STATUS Key_Sta, UI_KEY_VALUE Key_Val)
{
    UINT8                             Ret = 1;
    UI_Normal_Button_Container_Desc_t *Interface;
    Contacts_List_t                   *Contact;
    UINT16                            ContactTotal;
    INT8                              *Name;
    INT8                              *Number;
    UINT8                             Len;

    Contacts_Get_Contacts_Operation_List(&ContactTotal);

    if (KEY_RELEASED == Key_Sta)
    {
        switch (Key_Val)
        {
        case KEY_UP:
        case KEY_LEFT:
        case KEY_DOWN:
        case KEY_RIGHT:
            Interface = (UI_Normal_Button_Container_Desc_t *)Nav_Get_Param(ACT_ID_CONTACTS);
            Ret = Contacts_Press_Direction_Key(Key_Val,
                                               &Interface->ButtonContainer,
                                               &g_ContactsMng.InterfaceCtrl.FocusContact);
            break;

        case KEY_OK:
            if (0 != ContactTotal)
            {
                Ret = 0; // call the default key function
            }
            break;

        case KEY_SOFTLEFT:
            Contacts_Create_Contacts_Option();
            break;

        case KEY_SOFTRIGHT:
            Nav_Back(ACT_ID_ANY);
            break;

        case KEY_END:
            Nav_Home(ACT_ID_ANY);
            break;

        case KEY_DIAL:
            if (0 != ContactTotal)
            {
                Contact = g_ContactsMng.InterfaceCtrl.FocusContact;
                Len = strlen(Contact->ContactInfo->Number);
                if (0 == Len)
                {
                    Contacts_Create_No_Phone_Number();
                    break;
                }
                Len++;
                Number = (INT8 *)Hal_Mem_Alloc(Len);
                Hal_Mem_Copy(Number, Contact->ContactInfo->Number, Len);

                Len  = strlen(Contact->ContactInfo->Name) + 1;
                Name = (INT8 *)Hal_Mem_Alloc(Len);
                Hal_Mem_Copy(Name, Contact->ContactInfo->Name, Len);

                Contacts_Call_Req(Name, Number);
            }
            break;

        default:
            break;
        } /* switch */
    }

    return(Ret);
} /* Contacts_Key_Cb */

/**
 * Callback function for destroying Contacts interface which will be popped from stack
 * param (in) Ctrl: VOID *
 * return  VOID
 */
VOID Contacts_OnDestroy(VOID *Ctrl)
{
    UI_Normal_Button_Container_Desc_t *Interface = (UI_Normal_Button_Container_Desc_t *)Ctrl;
    UINT8 i;

    for (i = 0;i < UI_MAX_CONT_BTN_NUM;i++)
    {
        if (NULL != Interface->ButtonContainer.ContButton[i].BtnTxt)
        {
            Hal_Mem_Free(Interface->ButtonContainer.ContButton[i].BtnTxt);
        }
    }
    Hal_Mem_Free(Ctrl);
    g_ContactsMng.InterfaceCtrl.InterfaceId  = 0xFFFF;
    g_ContactsMng.InterfaceCtrl.FocusContact = NULL;
}

VOID Contacts_Set_ScrlBar_Pos_For_BtnCont(lv_obj_t * scrlbar, lv_obj_t * page, lv_coord_t scrl_h, lv_coord_t scrl_y)
{
    lv_coord_t size_tmp = 0;
    lv_coord_t hpad = lv_obj_get_style_pad_left(page, LV_PAGE_PART_BG);
    lv_coord_t vpad = lv_obj_get_style_pad_top(page, LV_PAGE_PART_BG);
    lv_coord_t ipad = lv_obj_get_style_pad_inner(page, LV_PAGE_PART_BG);
    lv_coord_t obj_w = lv_obj_get_width(page);
    lv_coord_t obj_h = lv_obj_get_height(page);
    lv_coord_t sb_ver_pad = CONTACTS_MATH_MAX(ipad, vpad);

    /*Vertical scrollbar*/
    if(scrl_h <= obj_h - 2 * vpad) {        /*Full sized scroll bar*/
        lv_obj_set_pos(scrlbar, obj_w - ipad - hpad, FP_TITLE_BAR_H + sb_ver_pad);
    } else {
        size_tmp = (obj_h * (obj_h - (2 * sb_ver_pad))) / (scrl_h + 2 * vpad);
        if(size_tmp < CONTACTS_SB_MIN_SIZE) size_tmp = CONTACTS_SB_MIN_SIZE;
        lv_obj_set_pos(scrlbar, obj_w - ipad - hpad,
                       FP_TITLE_BAR_H + sb_ver_pad +
                       (-(scrl_y - vpad) * (obj_h - size_tmp - 2 * sb_ver_pad)) / (scrl_h + 2 * vpad - obj_h));
    }
}

VOID Contacts_Set_ScrlBar_Size_For_BtnCont(lv_obj_t * scrlbar, lv_obj_t * page, lv_coord_t scrl_h)
{
    lv_coord_t size_tmp;
    lv_coord_t hpad = lv_obj_get_style_pad_left(page, LV_PAGE_PART_BG);
    lv_coord_t vpad = lv_obj_get_style_pad_top(page, LV_PAGE_PART_BG);
    lv_coord_t ipad = lv_obj_get_style_pad_inner(page, LV_PAGE_PART_BG);
    lv_coord_t obj_h = lv_obj_get_height(page);
    lv_coord_t sb_ver_pad = CONTACTS_MATH_MAX(ipad, hpad);

    /*Vertical scrollbar*/
    if(scrl_h <= obj_h - 2 * vpad) {        /*Full sized scroll bar*/
        lv_obj_set_size(scrlbar, 4, obj_h - 2 * sb_ver_pad);
    } else {
        size_tmp = (obj_h * (obj_h - (2 * sb_ver_pad))) / (scrl_h + 2 * vpad);
        if(size_tmp < CONTACTS_SB_MIN_SIZE) size_tmp = CONTACTS_SB_MIN_SIZE;
        lv_obj_set_size(scrlbar, 4, size_tmp);
    }
}

/**
 * Callback function for additional actions after Creating Contacts interface
 * param (in) Ctrl: VOID *
 * return  VOID
 */
VOID Contacts_OnCreate(VOID *Ctrl)
{
    UI_Normal_Button_Container_Desc_t *Interface = (UI_Normal_Button_Container_Desc_t *)Ctrl;
    lv_obj_t *                        Cont       = Interface->ButtonContainer.ContScrl.Container;
    UINT16                            ContactsCount;
    lv_coord_t                        ScrlH;

    Contacts_Get_Contacts_Operation_List(&ContactsCount);
    if (0 < ContactsCount)
    {
        ScrlH = ContactsCount * Interface->ButtonContainer.Height;
        Contacts_Set_ScrlBar_Size_For_BtnCont(Cont, Interface->ButtonContainer.List, ScrlH);
        Contacts_Set_ScrlBar_Pos_For_BtnCont(Cont, Interface->ButtonContainer.List, ScrlH, 0);
    }
}

/**
 * Callback function for additional actions after restoring Contacts interface
 * param (in) Ctrl: VOID *
 * return  VOID
 */
VOID Contacts_OnRestoreState(VOID *Ctrl)
{
    UI_Normal_Button_Container_Desc_t *Interface = (UI_Normal_Button_Container_Desc_t *)Ctrl;
    lv_obj_t *                        Cont       = Interface->ButtonContainer.ContScrl.Container;
    UINT16                            ContactsCount;
    lv_coord_t                        ScrlH;

    Contacts_Get_Contacts_Operation_List(&ContactsCount);
    if (0 < ContactsCount)
    {
        ScrlH = ContactsCount * Interface->ButtonContainer.Height;
        Contacts_Set_ScrlBar_Size_For_BtnCont(Cont, Interface->ButtonContainer.List, ScrlH);
        Contacts_Set_ScrlBar_Pos_For_BtnCont(Cont,
                                             Interface->ButtonContainer.List,
                                             ScrlH,
                                             - Interface->ButtonContainer.PosY);
    }
}

/**
 * Create Contacts interface
 * param (in) VOID
 * return  VOID
 */
VOID Contacts_Create_Contacts(VOID)
{
    UI_Normal_Button_Container_Desc_t *Interface;
    Nav_Func_List_t                   FuncList;
    UINT8                             Len = CONTACTS_MAX_NAME_LENGTH + CONTACTS_MAX_NUMBER_LENGTH +
                                            1;
    Contacts_List_t                   *Contact;
    lv_ll_t                           *ContactsList;
    UINT16                            ContactsCount;
    UINT8                             i;

    Interface =
        (UI_Normal_Button_Container_Desc_t *)Hal_Mem_Alloc(sizeof(UI_Normal_Button_Container_Desc_t));
    Hal_Mem_Set(Interface, 0, sizeof(UI_Normal_Button_Container_Desc_t));

    g_ContactsMng.InterfaceCtrl.InterfaceId = ACT_ID_CONTACTS;

    ContactsList = Contacts_Get_Contacts_Operation_List(&ContactsCount);

    Interface->TitleBar.TxtId      = PHONE_TEXT_ID_CONTACT;
    Interface->TitleBar.TxtAlign   = LV_LABEL_ALIGN_CENTER;
    Interface->TitleBar.LabelAlign = LV_ALIGN_IN_TOP_LEFT;

    Interface->Label.TxtAlign   = LV_LABEL_ALIGN_CENTER;
    Interface->Label.LabelAlign = LV_ALIGN_IN_TOP_LEFT;
    if (0 == ContactsCount)
    {
        Interface->Label.TxtId = PHONE_TEXT_ID_EMPTY;
    }
    else
    {
        Interface->Label.TxtId = LV_LANG_TXT_ID_NONE;

        Contact = _lv_ll_get_head(ContactsList);
        g_ContactsMng.InterfaceCtrl.FocusContact = Contact;
        for (i = 0;i < UI_MAX_CONT_BTN_NUM;i++)
        {
            if (Contact)
            {
                Interface->ButtonContainer.ContButton[i].Valid       = TRUE;
                Interface->ButtonContainer.ContButton[i].ButtonIndex = i;
                Interface->ButtonContainer.ContButton[i].TxtId       = LV_LANG_TXT_ID_NONE;
                Interface->ButtonContainer.ContButton[i].SymbolId2   = Contacts_Get_Contact_Memory_Symbol(Contact->ContactInfo->MemoryAndIndex);
                Interface->ButtonContainer.ContButton[i].BtnTxt      = (INT8 *)Hal_Mem_Alloc(Len);
                sprintf(Interface->ButtonContainer.ContButton[i].BtnTxt, "%s\n%s", Contact->ContactInfo->Name, Contact->ContactInfo->Number);
                Interface->ButtonContainer.ContButton[i].ReleaseFun = Contacts_Btn_Contact_Cb;

                Contact = _lv_ll_get_next(ContactsList, Contact);
            }
            else
            {
                break;
            }
        }

        /* if (0 != (FP_CONT_BAR_H % ContactsCount)) */
        /* { */
        /*     Interface->ButtonContainer.Height = FP_CONT_BAR_H / ContactsCount + 1; */
        /* } */
        /* else */
        /* { */
        /*     Interface->ButtonContainer.Height = FP_CONT_BAR_H / ContactsCount; */
        /* } */
        Interface->ButtonContainer.Height = FP_CONT_BAR_H / UI_MAX_CONT_BTN_NUM;
    }

    Interface->ButtonBar.ButtonL.ButtonIndex = 0;
    Interface->ButtonBar.ButtonL.Valid       = TRUE;
    Interface->ButtonBar.ButtonL.TxtId       = PHONE_TEXT_ID_OPT;

    Interface->ButtonBar.ButtonM.ButtonIndex = 1;
    Interface->ButtonBar.ButtonM.Valid       = TRUE;
    Interface->ButtonBar.ButtonM.TxtId       = PHONE_TEXT_ID_DETAILS;

    Interface->ButtonBar.ButtonR.ButtonIndex = 2;
    Interface->ButtonBar.ButtonR.Valid       = TRUE;
    Interface->ButtonBar.ButtonR.TxtId       = PHONE_TEXT_ID_BACK;

    Interface->KeyFunc = Contacts_Key_Cb;

    Hal_Mem_Set(&FuncList, 0, sizeof(Nav_Func_List_t));
    FuncList.OnShow          = UI_Normal_Button_Container_Create;
    FuncList.OnCreate        = Contacts_OnCreate;
    FuncList.OnRestoreState  = Contacts_OnRestoreState;
    FuncList.OnDestroy       = Contacts_OnDestroy;

    Nav_Forward(ACT_ID_ANY, ACT_ID_CONTACTS, &FuncList, Interface);
} /* Contacts_Create_Contacts */

/**
 * Create Contacts_Not_Ready interface
 * param (in) VOID
 * return  VOID
 */
VOID Contacts_Create_Contacts_Not_Ready(VOID)
{
    UI_Status_Desc_t *StatusDesc;
    Nav_Func_List_t  FuncList;

    StatusDesc = (UI_Status_Desc_t *)Hal_Mem_Alloc(sizeof(UI_Status_Desc_t));
    Hal_Mem_Set(StatusDesc, 0, sizeof(UI_Status_Desc_t));

    g_ContactsMng.InterfaceCtrl.InterfaceId = ACT_ID_CONTACTS_NOT_READY;
    g_ContactsMng.InterfaceCtrl.Ctrl        = (VOID *)StatusDesc;

    StatusDesc->ContLabel.TxtId      = PHONE_TEXT_ID_CONTACTS_NOT_READY;
    StatusDesc->ContLabel.TxtAlign   = LV_LABEL_ALIGN_LEFT;
    StatusDesc->ContLabel.LabelAlign = LV_ALIGN_IN_TOP_LEFT;
    StatusDesc->ContLabelAlign       = LV_ALIGN_IN_TOP_LEFT;

    StatusDesc->ContImg.Img  = LV_SYMBOL_WARNING;
    StatusDesc->ContImgAlign = LV_ALIGN_IN_TOP_RIGHT;

    StatusDesc->KeyFunc = Contacts_Status_Interface_Key_Cb;

    Hal_Mem_Set(&FuncList, 0, sizeof(Nav_Func_List_t));
    FuncList.OnShow    = UI_Status_Create;
    FuncList.OnCreate  = Contacts_Status_Interface_OnCreate;
    FuncList.OnDestroy = Contacts_Interface_OnDestroy;

    Nav_Forward(ACT_ID_ANY, ACT_ID_CONTACTS_NOT_READY, &FuncList, g_ContactsMng.InterfaceCtrl.Ctrl);
}

/**
 * Contacts APP main entrance
 * param (in) VOID
 * return  VOID
 */
VOID Contacts_Main(VOID)
{
    if (  (  (CONTACTS_PHONEBOOK_STATUS_SIM_ABSENT == g_ContactsMng.PhonebookStatus[0])
          || (CONTACTS_PHONEBOOK_STATUS_READ_DONE == g_ContactsMng.PhonebookStatus[0]))
       && (  (CONTACTS_PHONEBOOK_STATUS_SIM_ABSENT == g_ContactsMng.PhonebookStatus[1])
          || (CONTACTS_PHONEBOOK_STATUS_READ_DONE == g_ContactsMng.PhonebookStatus[1])))
    {
        Contacts_Create_Contacts();
    }
    else
    {
        Contacts_Create_Contacts_Not_Ready();
    }
}
/**
 * Compare two chinese characters in UTF-8 format
 * param (in) InBuf: INT8 *, UTF-8 code for chinese character
 * param (out) OutBuf: INT8 *, GB2312 code for chinese character
 * param (in) ArrayMaxNum: UINT8
 * param (in) Array: Contacts_UTF8_To_GB2312_Code_Index_t *
 * return  VOID
 */
VOID Contacts_Find_GB2312_Code(INT8 *InBuf, INT8 *OutBuf, UINT8 ArrayMaxNum, const Contacts_UTF8_To_GB2312_Code_Index_t *Array)
{
    UINT8 i = 0;
    UINT32 j = 0;
    UINT8   InBuf1 = 0;
    UINT8   InBuf2 = 0;
    INT8   GBCode1 = 0;
    INT8   GBCode2 = 0;
    UINT8 Result = false;
    UINT16 Temp = CONTACTS_MAX_TRANSLATE_GB_CODE; 

    Hal_Mem_Copy(&InBuf1,&InBuf[1],1);
    Hal_Mem_Copy(&InBuf2,&InBuf[2],1);
    for(i = 0;i < ArrayMaxNum;i++)
    {
        if(InBuf1 == Array[i].UTF8Byte2)
        {
            Result = true;
            break;
        }
    }
    if(true == Result)
    {
        for(j = Array[i].StartIndex;j < Array[i].StartIndex + Array[i].GBCnt;j++)
        {
            if(InBuf2 == UTF8_To_GB_Code[j].UTF8CodeByte3)
            {
                GBCode1 = UTF8_To_GB_Code[j].GBCode >> 8;
                GBCode2 = UTF8_To_GB_Code[j].GBCode & 0x00FF;
                Hal_Mem_Copy(&OutBuf[0],&GBCode1,1);
                Hal_Mem_Copy(&OutBuf[1],&GBCode2,1);
                break;
            }
        }
    }
    else
    {
        GBCode1 = Temp >> 8;
        GBCode2 = Temp & 0x00FF;
        Hal_Mem_Copy(&OutBuf[0],&GBCode1,1);
        Hal_Mem_Copy(&OutBuf[1],&GBCode2,1);
    }
}
/**
 * Compare two chinese characters in UTF-8 format
 * param (in) InBuf: INT8 *, UTF-8 code for chinese character
 * param (in) InLen: UINT8
 * param (out) OutBuf: INT8 *, GB2312 code for chinese character
 * param (out) OutLen: UINT8
 * return  VOID
 */
VOID Contacts_UTF8_To_GB2312(INT8 *InBuf, UINT8 InLen, INT8 *OutBuf, UINT8 OutLen)
{
    UINT8   InBuf0 = 0;
    UINT8   InBuf1 = 0;
    INT8   GBCode1 = 0;
    INT8   GBCode2 = 0;
    UINT16   Temp = CONTACTS_MAX_TRANSLATE_GB_CODE; 

    Hal_Mem_Copy(&InBuf0,InBuf,1);
    Hal_Mem_Copy(&InBuf1,&InBuf[1],1);
    switch (InBuf0)
    {
    case CONTACTS_UTF8_BYTE0_E4:
        switch (InBuf1 & 0xF0)
        {
        case CONTACTS_UTF8_BYTE1_4BIT_B0:
            Contacts_Find_GB2312_Code(InBuf,
                                      OutBuf,
                                      CONTACTS_E4_B_MAX_NUM,
                                      E4_BStart);
            break;
        default:
            GBCode1 = Temp >> 8;
            GBCode2 = Temp & 0x00FF;
            Hal_Mem_Copy(&OutBuf[0],&GBCode1,1);
            Hal_Mem_Copy(&OutBuf[1],&GBCode2,1);
            break;
        }
        break;
    case CONTACTS_UTF8_BYTE0_E5:
        switch (InBuf1 & 0xF0)
        {
        case CONTACTS_UTF8_BYTE1_4BIT_80:
            Contacts_Find_GB2312_Code(InBuf,
                                      OutBuf,
                                      CONTACTS_E5_8_MAX_NUM,
                                      E5_8Start);
            break;
        case CONTACTS_UTF8_BYTE1_4BIT_90:
            Contacts_Find_GB2312_Code(InBuf,
                                      OutBuf,
                                      CONTACTS_E5_9_MAX_NUM,
                                      E5_9Start);
            break;
        case CONTACTS_UTF8_BYTE1_4BIT_A0:
            Contacts_Find_GB2312_Code(InBuf,
                                      OutBuf,
                                      CONTACTS_E5_A_MAX_NUM,
                                      E5_AStart);
            break;
        case CONTACTS_UTF8_BYTE1_4BIT_B0:
            Contacts_Find_GB2312_Code(InBuf,
                                      OutBuf,
                                      CONTACTS_E5_B_MAX_NUM,
                                      E5_BStart);
            break;
        default:
            GBCode1 = Temp >> 8;
            GBCode2 = Temp & 0x00FF;
            Hal_Mem_Copy(&OutBuf[0],&GBCode1,1);
            Hal_Mem_Copy(&OutBuf[1],&GBCode2,1);
            break;
        }
        break;
    case CONTACTS_UTF8_BYTE0_E6:
        switch (InBuf1 & 0xF0)
        {
        case CONTACTS_UTF8_BYTE1_4BIT_80:
            Contacts_Find_GB2312_Code(InBuf,
                                      OutBuf,
                                      CONTACTS_E6_8_MAX_NUM,
                                      E6_8Start);
            break;
        case CONTACTS_UTF8_BYTE1_4BIT_90:
            Contacts_Find_GB2312_Code(InBuf,
                                      OutBuf,
                                      CONTACTS_E6_9_MAX_NUM,
                                      E6_9Start);
            break;
        case CONTACTS_UTF8_BYTE1_4BIT_A0:
            Contacts_Find_GB2312_Code(InBuf,
                                      OutBuf,
                                      CONTACTS_E6_A_MAX_NUM,
                                      E6_AStart);
            break;
        case CONTACTS_UTF8_BYTE1_4BIT_B0:
            Contacts_Find_GB2312_Code(InBuf,
                                      OutBuf,
                                      CONTACTS_E6_B_MAX_NUM,
                                      E6_BStart);
            break;
        default:
            GBCode1 = Temp >> 8;
            GBCode2 = Temp & 0x00FF;
            Hal_Mem_Copy(&OutBuf[0],&GBCode1,1);
            Hal_Mem_Copy(&OutBuf[1],&GBCode2,1);
            break;
        }
        break;
    case CONTACTS_UTF8_BYTE0_E7:
        switch (InBuf1 & 0xF0)
        {
        case CONTACTS_UTF8_BYTE1_4BIT_80:
            Contacts_Find_GB2312_Code(InBuf,
                                      OutBuf,
                                      CONTACTS_E7_8_MAX_NUM,
                                      E7_8Start);
            break;
        case CONTACTS_UTF8_BYTE1_4BIT_90:
            Contacts_Find_GB2312_Code(InBuf,
                                      OutBuf,
                                      CONTACTS_E7_9_MAX_NUM,
                                      E7_9Start);
            break;
        case CONTACTS_UTF8_BYTE1_4BIT_A0:
            Contacts_Find_GB2312_Code(InBuf,
                                      OutBuf,
                                      CONTACTS_E7_A_MAX_NUM,
                                      E7_AStart);
            break;
        case CONTACTS_UTF8_BYTE1_4BIT_B0:
            Contacts_Find_GB2312_Code(InBuf,
                                      OutBuf,
                                      CONTACTS_E7_B_MAX_NUM,
                                      E7_BStart);
            break;
        default:
            GBCode1 = Temp >> 8;
            GBCode2 = Temp & 0x00FF;
            Hal_Mem_Copy(&OutBuf[0],&GBCode1,1);
            Hal_Mem_Copy(&OutBuf[1],&GBCode2,1);
            break;
        }
        break;
    case CONTACTS_UTF8_BYTE0_E8:
        switch (InBuf1 & 0xF0)
        {
        case CONTACTS_UTF8_BYTE1_4BIT_80:
            Contacts_Find_GB2312_Code(InBuf,
                                      OutBuf,
                                      CONTACTS_E8_8_MAX_NUM,
                                      E8_8Start);
            break;
        case CONTACTS_UTF8_BYTE1_4BIT_90:
            Contacts_Find_GB2312_Code(InBuf,
                                      OutBuf,
                                      CONTACTS_E8_9_MAX_NUM,
                                      E8_9Start);
            break;
        case CONTACTS_UTF8_BYTE1_4BIT_A0:
            Contacts_Find_GB2312_Code(InBuf,
                                      OutBuf,
                                      CONTACTS_E8_A_MAX_NUM,
                                      E8_AStart);
            break;
        case CONTACTS_UTF8_BYTE1_4BIT_B0:
            Contacts_Find_GB2312_Code(InBuf,
                                      OutBuf,
                                      CONTACTS_E8_B_MAX_NUM,
                                      E8_BStart);
            break;
        default:
            GBCode1 = Temp >> 8;
            GBCode2 = Temp & 0x00FF;
            Hal_Mem_Copy(&OutBuf[0],&GBCode1,1);
            Hal_Mem_Copy(&OutBuf[1],&GBCode2,1);
            break;
        }
        break;
    case CONTACTS_UTF8_BYTE0_E9:
        switch (InBuf1 & 0xF0)
        {
        case CONTACTS_UTF8_BYTE1_4BIT_80:
            Contacts_Find_GB2312_Code(InBuf,
                                      OutBuf,
                                      CONTACTS_E9_8_MAX_NUM,
                                      E9_8Start);
            break;
        case CONTACTS_UTF8_BYTE1_4BIT_90:
            Contacts_Find_GB2312_Code(InBuf,
                                      OutBuf,
                                      CONTACTS_E9_9_MAX_NUM,
                                      E9_9Start);
            break;
        case CONTACTS_UTF8_BYTE1_4BIT_A0:
            Contacts_Find_GB2312_Code(InBuf,
                                      OutBuf,
                                      CONTACTS_E9_A_MAX_NUM,
                                      E9_AStart);
            break;
        case CONTACTS_UTF8_BYTE1_4BIT_B0:
            Contacts_Find_GB2312_Code(InBuf,
                                      OutBuf,
                                      CONTACTS_E9_B_MAX_NUM,
                                      E9_BStart);
            break;
        default:
            GBCode1 = Temp >> 8;
            GBCode2 = Temp & 0x00FF;
            Hal_Mem_Copy(&OutBuf[0],&GBCode1,1);
            Hal_Mem_Copy(&OutBuf[1],&GBCode2,1);
            break;
        }
        break;
    default:
        GBCode1 = Temp >> 8;
        GBCode2 = Temp & 0x00FF;
        Hal_Mem_Copy(&OutBuf[0],&GBCode1,1);
        Hal_Mem_Copy(&OutBuf[1],&GBCode2,1);
        break;
    } 
}

/**
 * Compare two chinese characters in UTF-8 format
 * param (in) Char1: INT8 *, 3 bytes for chinese character
 * param (in) Char2: INT8 *, 3 bytes for chinese character
 * return  INT8: 1, Char1 < Char2
 *               0, Char1 == Char2
 *               -1, Char1 > Char2
 *               -2, error
 */
INT8 Contacts_Compare_Chinese_Character(INT8 *Char1, INT8 *Char2)
{
    INT8 InBuf1[4]  = { 0 };
    INT8 OutBuf1[3] = { 0 };
    INT8 InBuf2[4]  = { 0 };
    INT8 OutBuf2[3] = { 0 };
    UINT8 i;

    if ((NULL == Char1) || (NULL == Char2))
    {
        /* error */
        return(-2);
    }

    if ((3 > strlen(Char1)) || (3 > strlen(Char2)))
    {
        /* error */
        return(-2);
    }

    Hal_Mem_Copy(InBuf1, Char1, 3);
    Hal_Mem_Copy(InBuf2, Char2, 3);

    Contacts_UTF8_To_GB2312(InBuf1, 4, OutBuf1, 3);
    Contacts_UTF8_To_GB2312(InBuf2, 4, OutBuf2, 3);
    for (i = 0;i < 3;i++)
    {
        if (OutBuf1[i] > OutBuf2[i])
        {
            return(-1);
        }
        else if (OutBuf1[i] < OutBuf2[i])
        {
            return(1);
        }
    }

    return(0);
}

/**
 * Compare two contacts by name,
 * rule: digit < lowercase letter < uppercase letter < chinese character,
 *       contact on phone < SIM1 < SIM2 if two names are the same
 *       short name < long name
 * param (in) New: Contacts_Info_t *
 * param (in) Node: Contacts_Info_t *
 * return  INT8: 1, New < Node
 *               0, the same contact
 *               -1, New > Node
 */
INT8 Contacts_Sort_Contact(Contacts_Info_t *New, Contacts_Info_t *Node)
{
    UINT8 i;
    UINT8 MemoryNew;
    UINT8 MemoryNode;
    INT8  Ret;
    UINT8 DValue = 'a' - 'A';

    if (0 == strcmp(New->Name, Node->Name))
    {
        MemoryNew  = Contacts_Get_Contact_Memory(New->MemoryAndIndex);
        MemoryNode = Contacts_Get_Contact_Memory(Node->MemoryAndIndex);
        if (MemoryNew < MemoryNode)
        {
            return(1);
        }
        else if (MemoryNew > MemoryNode)
        {
            return(-1);
        }
        else
        {
            return(0);
        }
    }

    for (i = 0; ; i++)
    {
        if ('\0' == Node->Name[i])
        {
            return(-1);
        }

        if ('\0' == New->Name[i])
        {
            return(1);
        }

        if (0 == (New->Name[i] & 0x80))      // ASCII
        {
            if (0 == (Node->Name[i] & 0x80)) // ASCII
            {
                if (  (',' == New->Name[i])
                   || ('.' == New->Name[i])
                   || ('?' == New->Name[i]))
                {
                    if (  (',' == Node->Name[i])
                       || ('.' == Node->Name[i])
                       || ('?' == Node->Name[i]))
                    {
                        if (New->Name[i] < Node->Name[i])
                        {
                            return(1);
                        }
                        else if (New->Name[i] > Node->Name[i])
                        {
                            return(-1);
                        }
                    }
                }
                else if (('0' <= New->Name[i]) && (New->Name[i] <= '9'))
                {
                    if (  (',' == Node->Name[i])
                       || ('.' == Node->Name[i])
                       || ('?' == Node->Name[i]))
                    {
                        return(-1);
                    }
                    else if (('0' <= Node->Name[i]) && (Node->Name[i] <= '9'))
                    {
                        if (New->Name[i] < Node->Name[i])
                        {
                            return(1);
                        }
                        else if (New->Name[i] > Node->Name[i])
                        {
                            return(-1);
                        }
                    }
                    else
                    {
                        return(1);
                    }
                }
                else if (('A' <= New->Name[i]) && (New->Name[i] <= 'Z'))
                {
                    if ('?' >= Node->Name[i]) // , . 0-9 ?
                    {
                        return(-1);
                    }
                    else if (('A' <= Node->Name[i]) && (Node->Name[i] <= 'Z'))
                    {
                        if (New->Name[i] < Node->Name[i])
                        {
                            return(1);
                        }
                        else if (New->Name[i] > Node->Name[i])
                        {
                            return(-1);
                        }
                    }
                    else if (('a' <= Node->Name[i]) && (Node->Name[i] <= 'z'))
                    {
                        if (New->Name[i] <= (Node->Name[i] - DValue))
                        {
                            return(1);
                        }
                        else
                        {
                            return(-1);
                        }
                    }
                }
                else if (('a' <= New->Name[i]) && (New->Name[i] <= 'z'))
                {
                    if ('?' >= Node->Name[i]) // , . 0-9 ?
                    {
                        return(-1);
                    }
                    else if (('A' <= Node->Name[i]) && (Node->Name[i] <= 'Z'))
                    {
                        if (New->Name[i] < (Node->Name[i] + DValue))
                        {
                            return(1);
                        }
                        else
                        {
                            return(-1);
                        }
                    }
                    else if (('a' <= Node->Name[i]) && (Node->Name[i] <= 'z'))
                    {
                        if (New->Name[i] < Node->Name[i])
                        {
                            return(1);
                        }
                        else if (New->Name[i] > Node->Name[i])
                        {
                            return(-1);
                        }
                    }
                }
            }
            else // chinese character
            {
                return(1);
            }
        }
        else // chinese character
        {
            if (0 == (Node->Name[i] & 0x80)) // ASCII
            {
                return(-1);
            }
            else // chinese character
            {
                Ret = Contacts_Compare_Chinese_Character(&New->Name[i], &Node->Name[i]);
                if (1 == Ret) /*New < Node*/
                {
                    return(1);
                }
                else if (-1 == Ret)
                {
                    return(-1);
                }

                i += 2;
            }
        }
    }
} /* Contacts_Names_Compare */

/**
 * Add contact into contact list
 * param (in/out) Focus: Contacts_List_t**, the starting position
 * param (in/out) FocusForContacts: Contacts_List_t**, get focus contact for CONTACTS interface
 * return  INT8: 1, add contact successfully; 0, the same contact on the same memory, not save
 */
UINT8 Contacts_Add_Contact(Contacts_Info_t *New, Contacts_List_t **Focus,
                           Contacts_List_t **FocusForContacts)
{
    Contacts_List_t *Node    = NULL;
    Contacts_List_t *Contact = NULL;
    INT8            Ret;

    /* Save new contact into ContactsList */
    if ((NULL == Focus) || (Focus && (NULL == *Focus)))
    {
        Node = _lv_ll_get_head(&g_ContactsMng.ContactsList);
    }
    else
    {
        Node = _lv_ll_get_next(&g_ContactsMng.ContactsList, *Focus);
    }

    while (NULL != Node)
    {
        Ret = Contacts_Sort_Contact(New, Node->ContactInfo);
        if (1 == Ret) /*New < Node*/
        {
            Contact = _lv_ll_ins_prev(&g_ContactsMng.ContactsList, Node);
            break;
        }
        else if (0 == Ret)
        {
            if (NULL != Focus)
            {
                *Focus = Node;
            }
            if (NULL != FocusForContacts)
            {
                *FocusForContacts = Node;
            }
            return(0);
        }

        Node = _lv_ll_get_next(&g_ContactsMng.ContactsList, Node);
    }
    if (NULL == Node)
    {
        Contact = _lv_ll_ins_tail(&g_ContactsMng.ContactsList);
    }
    Contact->ContactInfo = New;
    g_ContactsMng.ContactsCount++;

    if (NULL != Focus)
    {
        *Focus = Contact;
    }
    if (NULL != FocusForContacts)
    {
        *FocusForContacts = Contact;
    }

    /* Save new contact into MemSelList */
    if (CONTACTS_MEMSEL_ALL != g_ContactsMng.ContactsMemSel.MemSel)
    {
        if (Contacts_Is_In_MemSel(New->MemoryAndIndex, g_ContactsMng.ContactsMemSel.MemSel))
        {
            Node = _lv_ll_get_head(&g_ContactsMng.ContactsMemSel.ListForSpecMem);
            while (NULL != Node)
            {
                Ret = Contacts_Sort_Contact(New, Node->ContactInfo);
                if (1 == Ret)
                {
                    Contact = _lv_ll_ins_prev(&g_ContactsMng.ContactsMemSel.ListForSpecMem, Node);
                    break;
                }

                Node = _lv_ll_get_next(&g_ContactsMng.ContactsMemSel.ListForSpecMem, Node);
            }
            if (NULL == Node)
            {
                Contact = _lv_ll_ins_tail(&g_ContactsMng.ContactsMemSel.ListForSpecMem);
            }
            Contact->ContactInfo = New;
            g_ContactsMng.ContactsMemSel.ContactsCount++;
            if (NULL != FocusForContacts)
            {
                *FocusForContacts = Contact;
            }
        }
        else
        {
            /* the new contact not in the contact list for selected memory in settings function */
            if (NULL != FocusForContacts)
            {
                *FocusForContacts = NULL;
            }
        }
    }

    return(1);
} /* Contacts_Add_Contact */

/**
 * Reboot contacts module
 * param (in) VOID
 * return  VOID
 */
VOID Contacts_Reboot_Req(VOID)
{
    If_Framework_Reg_Info_t          *RegInfo;
    UINT32                           Len;
    NV_UI_Contacts_Bitmap_t          *NvBitmap;
    NV_UI_Contacts_Contact_List_t    *NvContactList;
    NV_UI_Contacts_Speed_Dial_List_t *NvSpeedDialList;
    NV_UI_Contacts_Num_Scrn_List_t   *NvNumScrnList;
    UINT8                            i;
    UINT8                            j;
    UINT16                           Index;
    Contacts_Info_t                  *NewContact;
    UINT8                            LastBit;
    UINT16                           LastIndex;

    g_ContactsMng.PhkStatus[CONTACTS_MEMORY_PHONE].Total = NV_CONTACTS_MAX_CONTACT_NUM;
    _lv_ll_init(&g_ContactsMng.ContactsList, sizeof(Contacts_List_t));
    _lv_ll_init(&g_ContactsMng.ContactsMemSel.ListForSpecMem, sizeof(Contacts_List_t));
    _lv_ll_init(&g_ContactsMng.ContactsSearch.SearchList, sizeof(Contacts_List_t));
    _lv_ll_init(&g_ContactsMng.ContactOper.SrcMemList, sizeof(Contacts_List_t));

    RegInfo             = (If_Framework_Reg_Info_t *)Hal_Mem_Alloc(sizeof(If_Framework_Reg_Info_t));
    RegInfo->NameTextId = PHONE_TEXT_ID_CONTACT;
    RegInfo->AppImage   = IMG_MENU_CONTACT;
    RegInfo->AppFunc    = Contacts_Main;
    Framework_App_Register_Req(RegInfo);

    /* read NVM */
    Len      = sizeof(NV_UI_Contacts_Bitmap_t);
    NvBitmap = (NV_UI_Contacts_Bitmap_t *)Hal_Mem_Alloc(Len);
    if (Len == UI_NV_Read_Req(NV_SECTION_UI_CONTACTS_BITMAP, 0, Len, (UINT8 *)NvBitmap))
    {
        if (0 == NvBitmap->MemSelBitmap)
        {
            g_ContactsMng.ContactsMemSel.MemSel = CONTACTS_MEMSEL_ALL;
        }
        else
        {
            g_ContactsMng.ContactsMemSel.MemSel = NvBitmap->MemSelBitmap;
        }
    }
    else
    {
        /* error */
    }

    /* Save contacts from NVM */
    LastIndex = (NV_CONTACTS_MAX_CONTACT_NUM - 1) / 8;
    LastBit   = (NV_CONTACTS_MAX_CONTACT_NUM - 1) % 8;

    Len           = sizeof(NV_UI_Contacts_Contact_List_t);
    NvContactList = (NV_UI_Contacts_Contact_List_t *)Hal_Mem_Alloc(Len);
    if (Len == UI_NV_Read_Req(NV_SECTION_UI_CONTACTS_LIST, 0, Len, (UINT8 *)NvContactList))
    {
        /* Save contacts from NVM */
        for (i = 0; i < NV_CONTACTS_MAX_BITMAP_LEN; i++)
        {
            if (0 == NvBitmap->ContactBitmap[i])
            {
                continue;
            }

            for (j = 0; j < 8; j++)
            {
                if (0 != (NvBitmap->ContactBitmap[i] & (0x01 << j)))
                {
                    Index      = i * 8 + j;
                    NewContact = (Contacts_Info_t *)Hal_Mem_Alloc(sizeof(Contacts_Info_t));
                    Hal_Mem_Set(NewContact, 0, sizeof(Contacts_Info_t));
                    Hal_Mem_Copy(NewContact->Name, NvContactList->ContactInfo[Index].Name, NV_CONTACTS_MAX_NAME_LEN);
                    Hal_Mem_Copy(NewContact->Number, NvContactList->ContactInfo[Index].Number, NV_CONTACTS_MAX_NUMBER_LEN);
                    NewContact->ToneIndex       = NvContactList->ContactInfo[Index].ToneIndex;
                    NewContact->MemoryAndIndex  = Contacts_Set_Contact_Memory(CONTACTS_MEMORY_PHONE);
                    NewContact->MemoryAndIndex += Index;

                    printf("%s: index %d, bit %d, name %s\n", __FUNCTION__, i, j, NvContactList->ContactInfo[Index].Name);
                    if (0 == Contacts_Add_Contact(NewContact, NULL, NULL))
                    {
                        /* error */
                        continue;
                    }

                    g_ContactsMng.PhkStatus[CONTACTS_MEMORY_PHONE].Used++;
                }

                if ((LastIndex == i) && (LastBit == j))
                {
                    break;
                }
            }
        }
    }
    else
    {
        /* error */
        return;
    }
    Hal_Mem_Free(NvBitmap);
    Hal_Mem_Free(NvContactList);

    Len             = sizeof(NV_UI_Contacts_Speed_Dial_List_t);
    NvSpeedDialList = (NV_UI_Contacts_Speed_Dial_List_t *)Hal_Mem_Alloc(Len);
    if (Len == UI_NV_Read_Req(NV_SECTION_UI_SPEED_DIAL_LIST, 0, Len, (UINT8 *)NvSpeedDialList))
    {
        /* Save speed dial list from NVM */
        Hal_Mem_Copy(g_ContactsMng.SpeedDialList, NvSpeedDialList->SpeedDialInfo, Len);
    }
    else
    {
        /* error */
    }
    Hal_Mem_Free(NvSpeedDialList);

    Len           = sizeof(NV_UI_Contacts_Num_Scrn_List_t);
    NvNumScrnList = (NV_UI_Contacts_Num_Scrn_List_t *)Hal_Mem_Alloc(Len);
    if (Len == UI_NV_Read_Req(NV_SECTION_UI_NUM_SCRN_LIST, 0, Len, (UINT8 *)NvNumScrnList))
    {
        /* Save number screening list from NVM */
        Hal_Mem_Copy(g_ContactsMng.NumScrnList, NvNumScrnList, Len);
    }
    else
    {
        /* error */
    }
    Hal_Mem_Free(NvNumScrnList);
}

/**
 * Initiate contacts module
 * param (in) VOID
 * return  VOID
 */
VOID Contacts_Init_Req(VOID)
{
    Hal_Mem_Set(&g_ContactsMng, 0, sizeof(Contacts_Mng_t));

    if (IF_FRAMEWORK_INIT_CHARGE == Framework_Get_Init_Type())
    {
        printf("%s: power off charging mode\n", __FUNCTION__);
        return;
    }

    Contacts_Reboot_Req();
} /* Contacts_Init_Req */

/**
 * Response for reading contacts from phone book
 * param (in) SimId: MMI_MODEM_SIM_ID
 * param (in) Contact: MMI_Modem_Contact*
 * param (in) Number: UINT16
 * param (in) End: BOOL
 * return  VOID
 */
VOID Phone_Modem_Read_Phonebook_Cnf(MMI_MODEM_SIM_ID SimId,
                                    MMI_Modem_Contact *Contact,
                                    UINT16 Number,
                                    BOOL End)
{
    MMI_MODEM_SIM_ID OtherSimId;
    UINT16           i;
    Contacts_Info_t  *New;

    if (CONTACTS_PHONEBOOK_STATUS_READING != g_ContactsMng.PhonebookStatus[SimId])
    {
        /* error */
        return;
    }

    UINT32 press_time = lv_tick_get();
    for (i = 0; i < Number; i++)
    {
        New = (Contacts_Info_t *)Hal_Mem_Alloc(sizeof(Contacts_Info_t));
        Hal_Mem_Set(New, 0, sizeof(Contacts_Info_t));
        Hal_Mem_Copy(New->Name, Contact[i].Name, MMI_MODEM_MAX_NAME_LEN);
        Hal_Mem_Copy(New->Number, Contact[i].Number, MMI_MODEM_MAX_NUMBER_LEN);
        if (MMI_MODEM_SIM_1 == SimId)
        {
            New->MemoryAndIndex = Contacts_Set_Contact_Memory(CONTACTS_MEMORY_SIM1);
        }
        else
        {
            New->MemoryAndIndex = Contacts_Set_Contact_Memory(CONTACTS_MEMORY_SIM2);
        }
        New->MemoryAndIndex += Contact[i].Index;
        New->ToneIndex       = IF_CONTACTS_DEFAULT_TONE;
#if 0
        if (0 == Contacts_Add_Contact(New, NULL, NULL))
        {
            /* error */
            continue;
        }
#else
        Contacts_Add_Contact_With_Name_Modified(New, NULL);
#endif
    }
    if (MMI_MODEM_SIM_1 == SimId)
    {
        printf("%s: --------------------tick elaps %d, End %d, used %d\n",
               __FUNCTION__, lv_tick_elaps(press_time), End, g_ContactsMng.PhkStatus[CONTACTS_MEMORY_SIM1].Used);
    }
    else
    {
        printf("%s: --------------------tick elaps %d, End %d, used %d\n",
               __FUNCTION__, lv_tick_elaps(press_time), End, g_ContactsMng.PhkStatus[CONTACTS_MEMORY_SIM2].Used);
    }

    g_ContactsMng.ContactOper.NameModifedFlg = FALSE; //can be modified in Contacts_Add_Contact_With_Name_Modified

    if (FALSE == End)
    {
        return;
    }

    g_ContactsMng.PhonebookStatus[SimId] = CONTACTS_PHONEBOOK_STATUS_READ_DONE;

    if (MMI_MODEM_SIM_1 == SimId)
    {
        OtherSimId = MMI_MODEM_SIM_2;
    }
    else
    {
        OtherSimId = MMI_MODEM_SIM_1;
    }
    if (  (CONTACTS_PHONEBOOK_STATUS_SIM_ABSENT == g_ContactsMng.PhonebookStatus[OtherSimId])
            || (CONTACTS_PHONEBOOK_STATUS_READ_DONE == g_ContactsMng.PhonebookStatus[OtherSimId]))
    {
        Contacts_Read_Contact_Complete();
    }
} /* MMI_Modem_Read_Phonebook_Cnf */

/**
 * Response for getting phone book status
 * param (in) SimId: MMI_MODEM_SIM_ID
 * param (in) PhkStatus: MMI_Modem_Phonebook_Status*
 * return  VOID
 */
VOID Phone_Modem_Get_Phonebook_Status_Cnf(MMI_MODEM_SIM_ID           SimId,
                                        MMI_Modem_Phonebook_Status *PhkStatus)
{
    MMI_MODEM_SIM_ID OtherSimId;
    UINT8            Memory;

    printf("%s: SimId %d, total %d, used %d, firstIndex %d, pb sta %d\n",
           __FUNCTION__, SimId, PhkStatus->total, PhkStatus->used, PhkStatus->firstIndex,
           g_ContactsMng.PhonebookStatus[SimId]);

    if (CONTACTS_PHONEBOOK_STATUS_READING != g_ContactsMng.PhonebookStatus[SimId])
    {
        /* error */
        return;
    }

    if (MMI_MODEM_SIM_1 == SimId)
    {
        Memory = CONTACTS_MEMORY_SIM1;
    }
    else
    {
        Memory = CONTACTS_MEMORY_SIM2;
    }

    g_ContactsMng.PhkStatus[Memory].Total      = PhkStatus->total;
    g_ContactsMng.PhkStatus[Memory].Used       = 0;
    g_ContactsMng.PhkStatus[Memory].FirstIndex = PhkStatus->firstIndex;

    if (0 < PhkStatus->used)
    {
        MMI_Modem_Read_Phonebook_Req(SimId, PhkStatus->used, PhkStatus->firstIndex);
    }
    else
    {
        g_ContactsMng.PhonebookStatus[SimId] = CONTACTS_PHONEBOOK_STATUS_READ_DONE;

        if (MMI_MODEM_SIM_1 == SimId)
        {
            OtherSimId = MMI_MODEM_SIM_2;
        }
        else
        {
            OtherSimId = MMI_MODEM_SIM_1;
        }
        if ((CONTACTS_PHONEBOOK_STATUS_SIM_ABSENT == g_ContactsMng.PhonebookStatus[OtherSimId])
            || (CONTACTS_PHONEBOOK_STATUS_READ_DONE == g_ContactsMng.PhonebookStatus[OtherSimId]))
        {
            Contacts_Read_Contact_Complete();
        }
    }

    Hal_Mem_Free(PhkStatus);
} /* MMI_Modem_Get_Phonebook_Status_Cnf */

/**
 * Indicate When phone book has been loaded by CP
 * param (in) SimId: MMI_MODEM_SIM_ID
 * return  VOID
 */
VOID Phone_Modem_Phonebook_Init_Ind(MMI_MODEM_SIM_ID SimId)
{
    MMI_MODEM_SIM_ID OtherSimId;

    UI_Log_Out(UI_SUB_MODULE_FRAMEWORK, UI_LOG_LEVEL_TRACE_1, "MMI_Modem_Phonebook_Init_Ind, SIM %d\n", SimId);

    if (MMI_MODEM_SIM_1 == SimId)
    {
        OtherSimId = MMI_MODEM_SIM_2;
    }
    else
    {
        OtherSimId = MMI_MODEM_SIM_1;
    }
    printf("%s: simid %d, pb sta %d, other pb sta %d\n",
           __FUNCTION__, SimId, g_ContactsMng.PhonebookStatus[SimId], g_ContactsMng.PhonebookStatus[OtherSimId]);
    switch (g_ContactsMng.PhonebookStatus[SimId])
    {
    case CONTACTS_PHONEBOOK_STATUS_UNKNOWN:
        g_ContactsMng.PhonebookStatus[SimId] = CONTACTS_PHONEBOOK_STATUS_UNKNOWN_INIT; // wait for sim status ind from framework
        break;

    case CONTACTS_PHONEBOOK_STATUS_NOT_INIT:
        MMI_Modem_Select_Character_Set_Req(SimId);
        g_ContactsMng.PhonebookStatus[SimId] = CONTACTS_PHONEBOOK_STATUS_READING;
        MMI_Modem_Get_Phonebook_Status_Req(SimId);
        break;

    default:
        break;
    }
}

/**
 * SIM status indicator from framework module
 * param (in) SimId: MMI_MODEM_SIM_ID
 * param (in) SimPresent: BOOL
 * return  VOID
 */
VOID Contacts_Sim_Status_Ind(MMI_MODEM_SIM_ID SimId, BOOL SimPresent)
{
    MMI_MODEM_SIM_ID OtherSimId;

    UI_Log_Out(UI_SUB_MODULE_FRAMEWORK, UI_LOG_LEVEL_TRACE_1, "Contacts_Sim_Status_Ind, SIM %d, Present %d\n", SimId, SimPresent);

    if (MMI_MODEM_SIM_1 == SimId)
    {
        OtherSimId = MMI_MODEM_SIM_2;
    }
    else
    {
        OtherSimId = MMI_MODEM_SIM_1;
    }

    switch (g_ContactsMng.PhonebookStatus[SimId])
    {
    case CONTACTS_PHONEBOOK_STATUS_UNKNOWN:
        if (TRUE == SimPresent)
        {
            g_ContactsMng.PhonebookStatus[SimId] = CONTACTS_PHONEBOOK_STATUS_NOT_INIT;
        }
        else
        {
            g_ContactsMng.PhonebookStatus[SimId] = CONTACTS_PHONEBOOK_STATUS_SIM_ABSENT;

            if ((CONTACTS_PHONEBOOK_STATUS_SIM_ABSENT == g_ContactsMng.PhonebookStatus[OtherSimId])
                || (CONTACTS_PHONEBOOK_STATUS_READ_DONE == g_ContactsMng.PhonebookStatus[OtherSimId]))
            {
                Contacts_Read_Contact_Complete();
            }
        }
        break;

    case CONTACTS_PHONEBOOK_STATUS_UNKNOWN_INIT:
        if (TRUE == SimPresent)
        {
            MMI_Modem_Select_Character_Set_Req(SimId); /*AT+CSCS="HEX"*/
            MMI_Modem_Get_Phonebook_Status_Req(SimId);
            g_ContactsMng.PhonebookStatus[SimId] = CONTACTS_PHONEBOOK_STATUS_READING;
        }
        else
        {
            g_ContactsMng.PhonebookStatus[SimId] = CONTACTS_PHONEBOOK_STATUS_SIM_ABSENT;

            if ((CONTACTS_PHONEBOOK_STATUS_SIM_ABSENT == g_ContactsMng.PhonebookStatus[OtherSimId])
                || (CONTACTS_PHONEBOOK_STATUS_READ_DONE == g_ContactsMng.PhonebookStatus[OtherSimId]))
            {
                Contacts_Read_Contact_Complete();
            }
        }
        break;

    default:
        break;
    } /* switch */
}     /* Contacts_Sim_Status_Ind */

/**
 * Compare the new number with the old number
 * param (in) New: INT8 *
 * param (in) Old: INT8 *
 * return  INT32: positive if New < Old, 0 if New == old, negative if New > Old
 */
INT32 Contacts_Compare_Number(INT8 *New, INT8 *Old)
{
    UINT8 NewLen;
    UINT8 OldLen;

    if (NULL == New)
    {
        return(-1);
    }

    if (NULL == Old)
    {
        return(1);
    }

    NewLen = strlen(New);
    OldLen = strlen(Old);
    if (NewLen < OldLen)
    {
        if ((8 == NewLen) || (11 == NewLen))
        {
            if (0 == strcmp(New, &Old[OldLen - NewLen]))
            {
                return(0);
            }
            else
            {
                return(-1);
            }
        }
        else
        {
            return(-1);
        }
    }
    else if (NewLen == OldLen)
    {
        return(strcmp(New, Old));
    }
    else
    {
        if ((8 == OldLen) || (11 == OldLen))
        {
            if (0 == strcmp(&New[NewLen - OldLen], Old))
            {
                return(0);
            }
            else
            {
                return(1);
            }
        }
        else
        {
            return(1);
        }
    }
}

/**
 * Get contact parameter related with phone number
 * param (in) Number: char *
 * param (out) ContactPara: If_Contacts_Contact_Para_t *
 * return  VOID
 */
VOID Contacts_Get_Contact_Para_Req(INT8 *Number, If_Contacts_Contact_Para_t *ContactPara)
{
    Contacts_List_t *Contact;
    UINT8           i;

    printf("%s: number %s\n", __FUNCTION__, Number);
    if (NULL == Number)
    {
        return;
    }

    if (NULL == ContactPara)
    {
        printf("%s: ContactPara is NULL\n", __FUNCTION__);
        return;
    }

    ContactPara->ToneIndex  = IF_CONTACTS_DEFAULT_TONE;
    ContactPara->NumScrnFlg = FALSE;
    Hal_Mem_Set(ContactPara->Name, 0, IF_CONTACTS_MAX_NAME_LENGTH);

    if(0 == strlen(Number)) {
        return;
    }

    Contact = _lv_ll_get_head(&g_ContactsMng.ContactsList);
    while (NULL != Contact)
    {
        if (0 == Contacts_Compare_Number(Number, Contact->ContactInfo->Number))
        {
            ContactPara->ToneIndex = Contact->ContactInfo->ToneIndex;
            Hal_Mem_Copy(ContactPara->Name, Contact->ContactInfo->Name, IF_CONTACTS_MAX_NAME_LENGTH);
            break;
        }

        Contact = _lv_ll_get_next(&g_ContactsMng.ContactsList, Contact);
    }
    for (i = 0; i < CONTACTS_MAX_NUM_SCRN_NUMBER; i++)
    {
        printf("%s: numscrnlist %d, %s\n", __FUNCTION__, i, g_ContactsMng.NumScrnList[i]);
        if (0 == Contacts_Compare_Number(Number, g_ContactsMng.NumScrnList[i]))
        {
            ContactPara->NumScrnFlg = TRUE;
            break;
        }
    }
    printf("%s: toneindex %d, scrnflg %d, name %s\n",
           __FUNCTION__, ContactPara->ToneIndex, ContactPara->NumScrnFlg, ContactPara->Name);
} /* Contacts_Get_Contact_Para_Req */

/**
 * Get contact number related with contact name
 * param (in) Name: char *
 * return  char *
 */
INT8 *Contacts_Get_Contact_Number_Req(INT8 *Name)
{
    Contacts_List_t *Contact;
    INT8            *Number = NULL;

    if (NULL == Name)
    {
        return(NULL);
    }

    Contact = _lv_ll_get_head(&g_ContactsMng.ContactsList);
    while (NULL != Contact)
    {
        if (0 == strcmp(Name, Contact->ContactInfo->Name))
        {
            Number = (INT8 *)Hal_Mem_Alloc(CONTACTS_MAX_NUMBER_LENGTH);
            Hal_Mem_Copy(Number, Contact->ContactInfo->Number, CONTACTS_MAX_NUMBER_LENGTH);
            break;
        }

        Contact = _lv_ll_get_next(&g_ContactsMng.ContactsList, Contact);
    }

    return(Number);
}

/**
 * Get contact list
 * param (in) VOID
 * return  If_Contacts_List_t *: header pointer of contact list, not free
 */
If_Contacts_List_t *Contacts_Get_Contact_List_Req(VOID)
{
    return(_lv_ll_get_head(&g_ContactsMng.ContactsList));
}

/**
 * Reset the descrition for Contacts interface after operation in deleting function
 * param (in) VOID
 * return  VOID
 */
VOID Contacts_Reset_Contacts_Interface(VOID)
{
    UI_Normal_Button_Container_Desc_t *Interface =
        (UI_Normal_Button_Container_Desc_t *)Nav_Get_Param(ACT_ID_CONTACTS);
    lv_ll_t                           *ContactsList;
    Contacts_List_t                   *Contact;
    UINT16                            ContactsCount;
    UINT8                             Len = CONTACTS_MAX_NAME_LENGTH + CONTACTS_MAX_NUMBER_LENGTH + 1;
    UINT8                             i;

    if (NULL == Interface)
    {
        printf("%s: not in contacts\n", __FUNCTION__);
        return;
    }

    ContactsList = Contacts_Get_Contacts_Operation_List(&ContactsCount);

    for (i = 0;i < UI_MAX_CONT_BTN_NUM;i++)
    {
        Interface->ButtonContainer.ContButton[i].Valid       = FALSE;
        Interface->ButtonContainer.ContButton[i].ButtonIndex = 0;
        Interface->ButtonContainer.ContButton[i].TxtId       = LV_LANG_TXT_ID_NONE;
        if (Interface->ButtonContainer.ContButton[i].BtnTxt)
        {
            Hal_Mem_Free(Interface->ButtonContainer.ContButton[i].BtnTxt);
            Interface->ButtonContainer.ContButton[i].BtnTxt = NULL;
        }
        Interface->ButtonContainer.ContButton[i].SymbolId1 = NULL;
        Interface->ButtonContainer.ContButton[i].SymbolId2 = NULL;
    }

    Interface->ButtonContainer.Index = 0;
    Interface->ButtonContainer.PosY  = 0;

    if (0 == ContactsCount)
    {
        Interface->Label.TxtId                   = PHONE_TEXT_ID_EMPTY;
        g_ContactsMng.InterfaceCtrl.FocusContact = NULL;

        ContactsCount = 1;
    }
    else
    {
        Interface->Label.TxtId = LV_LANG_TXT_ID_NONE;

        Contact                                  = _lv_ll_get_head(ContactsList);
        g_ContactsMng.InterfaceCtrl.FocusContact = Contact;
        for (i = 0;i < UI_MAX_CONT_BTN_NUM;i++)
        {
            if (Contact)
            {
                Interface->ButtonContainer.ContButton[i].Valid       = TRUE;
                Interface->ButtonContainer.ContButton[i].ButtonIndex = i;
                Interface->ButtonContainer.ContButton[i].TxtId       = LV_LANG_TXT_ID_NONE;
        
                Interface->ButtonContainer.ContButton[i].SymbolId2   = Contacts_Get_Contact_Memory_Symbol(Contact->ContactInfo->MemoryAndIndex);
                Interface->ButtonContainer.ContButton[i].BtnTxt      = (INT8 *)Hal_Mem_Alloc(Len);
                sprintf(Interface->ButtonContainer.ContButton[i].BtnTxt, "%s\n%s", Contact->ContactInfo->Name, Contact->ContactInfo->Number);
                Interface->ButtonContainer.ContButton[i].ReleaseFun = Contacts_Btn_Contact_Cb;

                Contact = _lv_ll_get_next(ContactsList, Contact);
            }
            else
            {
                break;
            }
        }
    }
} /* Contacts_Reset_Contacts_Interface */

/**
 * Send write phonebook req to modem
 * param (in) Memory: CONTACTS_MEMORY
 * param (in) Name: char *
 * param (in) Number: char *
 * param (in) Index: UINT8
 * return  VOID
 */
VOID Contacts_Send_Write_Phonebook_Req(CONTACTS_MEMORY Memory, char *Name, char *Number, UINT16 Index)
{
    MMI_Modem_Contact *SimContact;

    if (NULL == Name)
    {
        printf("%s: Memory %d,Index %d\n", __FUNCTION__, Memory, Index);
    }
    else
    {
        printf("%s: Memory %d,Index %d, Name %s, Number %s\n", __FUNCTION__, Memory, Index, Name, Number);
    }

    SimContact = (MMI_Modem_Contact *)Hal_Mem_Alloc(sizeof(MMI_Modem_Contact));
    Hal_Mem_Set(SimContact, 0, sizeof(MMI_Modem_Contact));
    SimContact->Index = Index;
    if (MMI_MODEM_CONTACT_INDEX_INVALID == SimContact->Index)
    {
        if ((NULL == Name) || (NULL == Number))
        {
            printf("%s: Name or Number is NULL\n", __FUNCTION__);
            return;
        }
        Hal_Mem_Copy(SimContact->Name, Name, CONTACTS_MAX_NAME_LENGTH);
        Hal_Mem_Copy(SimContact->Number, Number, CONTACTS_MAX_NUMBER_LENGTH);
    }

    g_ContactsMng.ContactOper.WaitCnfBitmap |= 1 << Memory;

    if (CONTACTS_MEMORY_SIM1 == Memory)
    {
        MMI_Modem_Write_Phonebook_Req(MMI_MODEM_SIM_1, SimContact);
    }
    else if (CONTACTS_MEMORY_SIM2 == Memory)
    {
        MMI_Modem_Write_Phonebook_Req(MMI_MODEM_SIM_2, SimContact);
    }
    else
    {
        printf("%s: memory %d error\n", __FUNCTION__, Memory);
    }
}

/**
 * Result for writing phonebook
 * param (in) SimId: MMI_MODEM_SIM_ID
 * param (in) WrittenIndex: UINT16
 * return  VOID
 */
VOID Phone_Modem_Write_Phonebook_Cnf(MMI_MODEM_SIM_ID SimId, UINT16 WrittenIndex)
{
    CONTACTS_MEMORY Memory;

    UI_Log_Out(UI_SUB_MODULE_FRAMEWORK, UI_LOG_LEVEL_TRACE_1,
               "MMI_Modem_Write_Phonebook_Cnf,sim %d,Index %d,Act %d,MarkNum %d,wait %d\n",
               SimId, WrittenIndex, g_ContactsMng.ContactOper.Action,
               g_ContactsMng.ContactOper.MarkNum, g_ContactsMng.ContactOper.WaitCnfBitmap);

    if (MMI_MODEM_SIM_1 == SimId)
    {
        g_ContactsMng.ContactOper.WaitCnfBitmap &= ~(1 << CONTACTS_MEMORY_SIM1);
    }
    else if (MMI_MODEM_SIM_2 == SimId)
    {
        g_ContactsMng.ContactOper.WaitCnfBitmap &= ~(1 << CONTACTS_MEMORY_SIM2);
    }

    if (CONTACTS_ACTION_NULL == g_ContactsMng.ContactOper.Action)
    {
        return;
    }

    if (CONTACTS_ACTION_DELETE == g_ContactsMng.ContactOper.Action)
    {
        if ((0 == g_ContactsMng.ContactOper.MarkNum)
            || g_ContactsMng.ContactOper.ProcQuit)
        {
            Contacts_Process_Delete_End_Handle();
            return;
        }

        Contacts_Process_Delete_Multiple_Contacts();
    }
    else if (CONTACTS_ACTION_COPYING == g_ContactsMng.ContactOper.Action)
    {
        g_ContactsMng.InterfaceCtrl.ContactDetail->MemoryAndIndex += WrittenIndex;

        Memory = g_ContactsMng.ContactOper.DestMemory;
        if ((0 == g_ContactsMng.ContactOper.MarkNum)
            || g_ContactsMng.ContactOper.ProcQuit
            || (g_ContactsMng.PhkStatus[Memory].Used == g_ContactsMng.PhkStatus[Memory].Total))
        {
            Contacts_Process_Copy_End_Handle();
            return;
        }

        Contacts_Process_Copy_Multiple_Contacts();
    }
    else if (CONTACTS_ACTION_MOVING == g_ContactsMng.ContactOper.Action)
    {
        Memory = g_ContactsMng.ContactOper.DestMemory;
        if (((CONTACTS_MEMORY_SIM1 == Memory)
             && (MMI_MODEM_SIM_1 == SimId))
            || ((CONTACTS_MEMORY_SIM2 == Memory)
                && (MMI_MODEM_SIM_2 == SimId)))
        {
            g_ContactsMng.InterfaceCtrl.ContactDetail->MemoryAndIndex += WrittenIndex;
        }

        if (0 == g_ContactsMng.ContactOper.WaitCnfBitmap)
        {
            if ((0 == g_ContactsMng.ContactOper.MarkNum)
                || g_ContactsMng.ContactOper.ProcQuit
                || (g_ContactsMng.PhkStatus[Memory].Used == g_ContactsMng.PhkStatus[Memory].Total))
            {
                Contacts_Process_Move_End_Handle();
                return;
            }
            Contacts_Process_Move_Multiple_Contacts();
        }
    }
    else if (CONTACTS_ACTION_ADD == g_ContactsMng.ContactOper.Action)
    {
        g_ContactsMng.InterfaceCtrl.Focus->ContactInfo->MemoryAndIndex += WrittenIndex;

        g_ContactsMng.InterfaceCtrl.FocusContact = g_ContactsMng.InterfaceCtrl.Focus;
        g_ContactsMng.InterfaceCtrl.Focus        = NULL;
        Contacts_Update_Contacts_Interface();

        if (MMI_MODEM_SIM_1 == SimId)
        {
            Contacts_Create_Contacts_Saved(PHONE_TEXT_ID_CONTACT_SAVED_SIM1);
        }
        else
        {
            Contacts_Create_Contacts_Saved(PHONE_TEXT_ID_CONTACT_SAVED_SIM2);
        }
    }
    else if (CONTACTS_ACTION_ADD_REQ == g_ContactsMng.ContactOper.Action)
    {
        g_ContactsMng.InterfaceCtrl.Focus->ContactInfo->MemoryAndIndex += WrittenIndex;
        g_ContactsMng.InterfaceCtrl.Focus = NULL;

        if (MMI_MODEM_SIM_1 == SimId)
        {
            Contacts_Create_Contacts_Saved(PHONE_TEXT_ID_CONTACT_SAVED_SIM1);
        }
        else
        {
            Contacts_Create_Contacts_Saved(PHONE_TEXT_ID_CONTACT_SAVED_SIM2);
        }
    }
    else if (CONTACTS_ACTION_REPLACE_PHASE_1 == g_ContactsMng.ContactOper.Action)
    {
        g_ContactsMng.ContactOper.Action = CONTACTS_ACTION_REPLACE_PHASE_2;

        /* add the new contact to SIM */
        Contacts_Send_Write_Phonebook_Req(g_ContactsMng.ContactOper.DestMemory,
                                          g_ContactsMng.InterfaceCtrl.Focus->ContactInfo->Name,
                                          g_ContactsMng.InterfaceCtrl.Focus->ContactInfo->Number,
                                          MMI_MODEM_CONTACT_INDEX_INVALID);
    }
    else if (CONTACTS_ACTION_REPLACE_PHASE_2 == g_ContactsMng.ContactOper.Action)
    {
        g_ContactsMng.ContactOper.Action = CONTACTS_ACTION_NULL;
        g_ContactsMng.InterfaceCtrl.Focus->ContactInfo->MemoryAndIndex
            = Contacts_Set_Contact_Memory(g_ContactsMng.ContactOper.DestMemory);
        g_ContactsMng.InterfaceCtrl.Focus->ContactInfo->MemoryAndIndex += WrittenIndex;
        if (NULL != Nav_Get_Param(ACT_ID_CONTACTS)) // Contacts interface in the stack
        {
            g_ContactsMng.InterfaceCtrl.FocusContact = g_ContactsMng.InterfaceCtrl.Focus;
            Contacts_Update_Contacts_Interface();
        }
        g_ContactsMng.InterfaceCtrl.Focus = NULL;

        Contacts_Create_Contacts_Saved(PHONE_TEXT_ID_REPLACED);
    }
    else if (CONTACTS_ACTION_EDIT_PHASE_1 == g_ContactsMng.ContactOper.Action)
    {
        g_ContactsMng.ContactOper.Action = CONTACTS_ACTION_EDIT_PHASE_2;

        if (MMI_MODEM_SIM_1 == SimId)
        {
            Memory = CONTACTS_MEMORY_SIM1;
        }
        else
        {
            Memory = CONTACTS_MEMORY_SIM2;
        }
        Contacts_Send_Write_Phonebook_Req(Memory,
                                          g_ContactsMng.InterfaceCtrl.ContactDetail->Name,
                                          g_ContactsMng.InterfaceCtrl.ContactDetail->Number,
                                          MMI_MODEM_CONTACT_INDEX_INVALID);
    }
    else if (CONTACTS_ACTION_EDIT_PHASE_2 == g_ContactsMng.ContactOper.Action)
    {
        g_ContactsMng.ContactOper.Action = CONTACTS_ACTION_NULL;

        /*save the index*/
        if (MMI_MODEM_SIM_1 == SimId)
        {
            g_ContactsMng.InterfaceCtrl.ContactDetail->MemoryAndIndex
                = Contacts_Set_Contact_Memory(CONTACTS_MEMORY_SIM1);
            Contacts_Create_Contacts_Saved(PHONE_TEXT_ID_CONTACT_SAVED_SIM1);
        }
        else
        {
            g_ContactsMng.InterfaceCtrl.ContactDetail->MemoryAndIndex
                = Contacts_Set_Contact_Memory(CONTACTS_MEMORY_SIM2);
            Contacts_Create_Contacts_Saved(PHONE_TEXT_ID_CONTACT_SAVED_SIM2);
        }
        g_ContactsMng.InterfaceCtrl.ContactDetail->MemoryAndIndex += WrittenIndex;
    }
} /* MMI_Modem_Write_Phonebook_Cnf */
